From 1275ad8c5c9368b541e7eeccfeb6bf20352e6330 Mon Sep 17 00:00:00 2001 From: razvanm Date: Sat, 2 Jun 2007 00:09:14 +0000 Subject: [PATCH] Add support for MicaZ to Deluge T2. --- apps/tests/deluge/Blink/BlinkAppC.nc | 5 +- apps/tests/deluge/Blink/burn | 27 +++-- apps/tests/deluge/Blink/volumes-at45db.xml | 4 + .../deluge/GoldenImage/volumes-at45db.xml | 4 + .../deluge/SerialBlink/volumes-at45db.xml | 4 + doc/html/deluge-t2-manual.html | 97 +++++++++++------- doc/pdf/deluge-t2-manual.pdf | Bin 44230 -> 45764 bytes tools/tinyos/misc/Makefile.am | 8 +- tools/tinyos/misc/tinyos.py | 29 +++++- tools/tinyos/misc/tos-deluge | 55 +++++----- tos/lib/TOSBoot/TOSBootM.nc | 24 +++-- tos/lib/net/Deluge/DelugeC.nc | 4 +- tos/lib/net/Deluge/DelugePageTransfer.h | 9 +- tos/lib/net/Deluge/DelugeStorage.nc | 55 ++++++++++ tos/lib/net/Deluge/DelugeStorageC.nc | 38 ++++--- tos/lib/net/Deluge/DelugeStorageP.nc | 29 ++++++ .../FlashVolumeManager/FlashVolumeManagerC.nc | 8 +- .../FlashVolumeManager/FlashVolumeManagerP.nc | 38 +++++-- tos/lib/net/Deluge/extra/NetProgC.nc | 7 +- tos/lib/net/Deluge/extra/NetProgM.nc | 7 +- .../net/Deluge/extra/avr/InternalFlashC.nc | 65 ++++++++++++ .../net/Deluge/extra/mica2/NetProg_platform.h | 44 ++++++++ .../net/Deluge/extra/micaz/InternalFlash.h | 41 ++++++++ .../net/Deluge/extra/micaz/TOSBoot_platform.h | 47 +++++++++ 24 files changed, 533 insertions(+), 116 deletions(-) create mode 100644 apps/tests/deluge/Blink/volumes-at45db.xml create mode 100644 apps/tests/deluge/GoldenImage/volumes-at45db.xml create mode 100644 apps/tests/deluge/SerialBlink/volumes-at45db.xml create mode 100644 tos/lib/net/Deluge/DelugeStorage.nc create mode 100644 tos/lib/net/Deluge/extra/avr/InternalFlashC.nc create mode 100644 tos/lib/net/Deluge/extra/mica2/NetProg_platform.h create mode 100644 tos/lib/net/Deluge/extra/micaz/InternalFlash.h create mode 100644 tos/lib/net/Deluge/extra/micaz/TOSBoot_platform.h diff --git a/apps/tests/deluge/Blink/BlinkAppC.nc b/apps/tests/deluge/Blink/BlinkAppC.nc index dae60f6a..4cdad48b 100644 --- a/apps/tests/deluge/Blink/BlinkAppC.nc +++ b/apps/tests/deluge/Blink/BlinkAppC.nc @@ -42,7 +42,10 @@ configuration BlinkAppC } implementation { - components MainC, BlinkC, LedsC, DelugeC; + components MainC, BlinkC, LedsC; +#ifdef DELUGE + components DelugeC; +#endif components new TimerMilliC() as Timer0; BlinkC -> MainC.Boot; diff --git a/apps/tests/deluge/Blink/burn b/apps/tests/deluge/Blink/burn index 8bb82a30..1418e382 100755 --- a/apps/tests/deluge/Blink/burn +++ b/apps/tests/deluge/Blink/burn @@ -1,21 +1,36 @@ #!/bin/bash -if [ $# -ne 1 ]; then - echo "Usage: $0 /dev/ttyUSB0" +if [ $# -ne 2 ]; then + echo "Usage: $0 " + echo " For example, /dev/ttyUSB0" + echo " \"micaz\", \"telosb\"" + exit 2 +fi + +if [ $2 != 'micaz' -a $2 != 'telosb' ]; then + echo "\"$2\" is not a supported platform" exit 2 fi PORT=$1 +PLATFORM=$2 + make clean echo ==================== Compile and load Blink ==================== -make telosb install bsl,$PORT +if [ $PLATFORM == 'micaz' ] +then + CFLAGS=-DDELUGE_BASESTATION make $PLATFORM install mib510,$PORT +elif [ $PLATFORM == 'telosb' ] +then + CFLAGS=-DDELUGE_BASESTATION make $PLATFORM install bsl,$PORT +fi echo ==================== Compile a new Blink ==================== -CFLAGS=-DBLINK_REVERSE make telosb +CFLAGS=-DBLINK_REVERSE\ -DDELUGE_BASESTATION make $PLATFORM echo ==================== Upload the image ==================== -../../../../tools/tinyos/misc/tos-deluge $PORT -i 0 build/telosb/tos_image.xml +../../../../tools/tinyos/misc/tos-deluge $PORT $PLATFORM -i 0 build/$PLATFORM/tos_image.xml echo ==================== Reboot ==================== -../../../../tools/tinyos/misc/tos-deluge $PORT -r 0 +../../../../tools/tinyos/misc/tos-deluge $PORT $PLATFORM -r 0 diff --git a/apps/tests/deluge/Blink/volumes-at45db.xml b/apps/tests/deluge/Blink/volumes-at45db.xml new file mode 100644 index 00000000..afc864a7 --- /dev/null +++ b/apps/tests/deluge/Blink/volumes-at45db.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/apps/tests/deluge/GoldenImage/volumes-at45db.xml b/apps/tests/deluge/GoldenImage/volumes-at45db.xml new file mode 100644 index 00000000..afc864a7 --- /dev/null +++ b/apps/tests/deluge/GoldenImage/volumes-at45db.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/apps/tests/deluge/SerialBlink/volumes-at45db.xml b/apps/tests/deluge/SerialBlink/volumes-at45db.xml new file mode 100644 index 00000000..afc864a7 --- /dev/null +++ b/apps/tests/deluge/SerialBlink/volumes-at45db.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/doc/html/deluge-t2-manual.html b/doc/html/deluge-t2-manual.html index 94b0de52..e865db12 100644 --- a/doc/html/deluge-t2-manual.html +++ b/doc/html/deluge-t2-manual.html @@ -22,7 +22,7 @@ Deluge T2 - Programming Manual

Chieh-Jan Mike Liang
-Razvan Musaloiu-E.

May 25, 2007

+Razvan Musaloiu-E.

June 1, 2007

@@ -45,14 +45,37 @@ Having said that, it would be helpful to read the Deluge 2.0 manual and related documentations.

Deluge T2 is still in experimental phase. One current limitation is -platform support. Deluge T2 has been developed and tested on Tmote Sky -(telosb) only. In addition, Deluge T2 comes with 2 flash volumes by +platform support. Deluge T2 has been developed on Tmote Sky (telosb) +and MicaZ only. In addition, Deluge T2 comes with 2 flash volumes by default. However, more volumes can be added, if necessary. There are -also minor details that will be improved in future releases.

+also some minor details that will be improved in future releases.

-

2  Quick Start

+

2  Tools Installation

+

Deluge T2 requires a few Python scripts that not yet included in the +official tinyos-tools RPM package. On the CVS, the scripts are +located in tinyos-2.x/tools/tinyos/misc. The steps to install +them are the following:

+

+

+
  % cd $TOSROOT
+  % ./Bootstrap
+      ...
+  % ./configure
+      ...
+  % cd tinyos/misc
+  % make ; make install
+      ...
+

+

+By default, the files will be installed in /usr/local/bin. If +desired, the --prefix parameter from configure can be +used to indicate a different path.

+

+

+ +

3  Quick Start

This section introduces the basics of reprogramming with an example. In @@ -68,7 +91,7 @@ For example, Then, we run the burn script provided in tinyos-2.x/apps/tests/deluge/Blink. For example,

-
   % ./burn /dev/ttyUSB0
+
   % ./burn /dev/ttyUSB0 telosb
 

This burn script programs the directly-connected mote with one version of Blink. Then, it injects and reprograms the mote with another @@ -76,7 +99,7 @@ version of Blink. At this point, you can try to retrieve program image versioning information. The script to interface with the mote is provided in tinyos-2.x/tools/tinyos/misc. For example,

-
   % tos-deluge /dev/ttyUSB0 -p 0
+
   % tos-deluge /dev/ttyUSB0 telosb -p 0
 

You should see something similar to the output below.

@@ -99,11 +122,11 @@ You should see something similar to the output below.

The usage of tos-deluge is available by running the script without -any arguments, and it will be discussed in section 4.

+any arguments, and it will be discussed in section 5.

- -

3  Reprogramming a Network

+ +

4  Reprogramming a Network

This section illustrates the procedure to reprogram a network. @@ -111,8 +134,8 @@ Specifically, we will see how program images are injected and how versioning information is retrieved.

- -

3.1  Setting Up the Motes

+ +

4.1  Setting Up the Motes

We first install both TOSBoot and a program that runs Deluge T2. For simplicity, we use the golden image as the program. The golden image is provided in tinyos-2.x/apps/tests/deluge/GoldenImage, and it does @@ -126,14 +149,14 @@ act as a base station, which requires an additional component to accept user commands from the serial port. Normally, only one mote in the network needs to be the base station, and other motes are reprogrammed over-the-air. If error occurs when running the command above, you might -need to compile TOSBoot as shown in section 2. +need to compile TOSBoot as shown in section 3. Deluge T2 makes sure the mote ID remain persistent over image reprogramming. You can test the installation by interacting with the mote through tos-deluge.

- -

3.2  Preparing Your Application

+ +

4.2  Preparing Your Application

In most cases, the only two files you need to modify are the top-level wiring file and the Makefile. You need to make sure DelugeC component is included. In addition, the Makefile should have the @@ -148,12 +171,12 @@ example,

- -

3.3  Injecting Your Application

+ +

4.3  Injecting Your Application

Before a program image is disseminated in the network, we need to first inject it to the base station. For example,

-
   % tos-deluge /dev/ttyUSB0 -i 1 apps/Blink/build/telosb/tos_image.xml
+
   % tos-deluge /dev/ttyUSB0 telosb -i 1 apps/Blink/build/telosb/tos_image.xml
 

You should see something similar to the output below.

@@ -184,13 +207,13 @@ You should see something similar to the output below.

- -

3.4  Reprogramming with New Image

+ +

4.4  Reprogramming with New Image

After you decide which program image you want to reprogram, you can first test on the base station by issuing the reboot command. For example,

-
   % tos-deluge /dev/ttyUSB0 -r 1
+
   % tos-deluge /dev/ttyUSB0 telosb -r 1
 

After a few moments, the mote will begin quickly flashing the LEDs to signify the reprogramming process.

@@ -198,7 +221,7 @@ signify the reprogramming process.

Now, you can have the base station disseminate a program image to the rest of the network. For example,

-
   % tos-deluge /dev/ttyUSB0 -d 1
+
   % tos-deluge /dev/ttyUSB0 telosb -d 1
 

This command instructs the base station to notify the whole network of the availablility of a new program image. This notification is currently @@ -207,8 +230,8 @@ network to get the new program image. Upon receiving the complete image over-the-air, each node automatically reboots and reprograms itself.

- -

4  Deluge T2 Python Toolchain

+ +

5  Deluge T2 Python Toolchain

Different from Deluge 2.0, Deluge T2 toolchain is written in Python. @@ -216,49 +239,49 @@ However, as demonstrated in the previous section, the usage is very similar.

- -

4.1  -p -ping

+ +

5.1  -p -ping

This command is useful for checking the status of program images on a mote. It provides information such as program name, compile time, size of the image, and so on.

- -

4.2  -i -inject

+ +

5.2  -i -inject

This command creates a program image from the supplied tos_image.xml file, and it injects the image into specified volume on the mote. All versioning information is kept on the mote, so no state is stored on the PC.

- -

4.3  -r -reboot

+ +

5.3  -r -reboot

This command sets up the mote to reprogram itself after reboot, and then it reboots the mote. This command is applicable only to the directly connected mote.

- -

4.4  -d -dissemination

+ +

5.4  -d -dissemination

This command instructs the directly connected mote to disseminate an image to the network. This image is specified by the volume ID. Upon successfully receiving an image, motes in the network automatically reprogram themselves.

- -

4.5  -e -erase

+ +

5.5  -e -erase

This command erases a flash volume on the directly connected mote.

- -

4.6  -s -reset

+ +

5.6  -s -reset

This command resets versioning information of a specific image on the directly connected mote.

-Last modified: Friday, May 25th, 2007
+Last modified: Friday, June 1st, 2007
HTML conversion by TeX2page 2004-09-11
diff --git a/doc/pdf/deluge-t2-manual.pdf b/doc/pdf/deluge-t2-manual.pdf index e50622d95a6364a04e9f34756e5657dfffc81280..0305fa58f834a4f95eb4bc8a1fcb259f2a6b4e03 100644 GIT binary patch delta 33082 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

#z;klFfC3 zzz710OD<{dL6N&s=wF|zzN)&X=k4+ktN_7+;Gkx@ySlpWs(wG7h((?V{44)Iy?h`} zzJY(|4}N?g)0>m>-_y&JFHRqP_7`bR;u4*5=H&GGgFH;0cy;2XSOfqsAAkI9ce+1_ z#RO@!-M!dLcr-@up6w5EQA!)LyK2CP`-9eQF+T2o-YdO0t?)yw04DtI&HiAQpo9p! z+cZW81*2h%UA$Dgo4sC)abA{ntT1&QBiw(T{sB>T9AzJtpnU|iPtO3=ANB{c#2~zf z1@O^FYjD{Ly=u@hTSow87JqGHsI$EV%zz5o?VdIy_#R&F#o~>!YWKSB<_32w7q4Ui z;vUKvW%cfQFT*0E-u<*cs6`1aY?;SI*!Ni)qin4ERzU;spru@#XDeRS$!AmvVo^Rc zs@xDMUeaSBg%@%6j-c1{_?8|I^sOT3LXZDLkDt-EPYC*Y`uKJ_?0;tO7vUr9_Zj~b zfI%fLnUBXo2G015fX~{X3j*FY;5q+tGSe3XyhuQ=)S86A`DXX(C}TJ?-XdlO(ulm)Us$(P1Jt z>NPm;57KLT@gJ|(l-G;Zdac)_mW6vm@F-OH6hX(aIiC5BJYA_*+sfMo z$LB43>)7nw7*N-6;1;ZAVj2MyrH$q(f>kw|)xwTXfc;KNhe z@yh6<+RDQtY#yBpAr{?eg9;A$G60dCVL%%5_q|z+7EVoA1ZSs1KwgY$5iW4;O30Vf zG*NLfGDJtQkls~hijKI=1|&DE1@aj!=nR!9p2a2#+keCgHnJ%-T7uu>Hl@bEMvP-) zMz+Ht?8Bd#t{V9+&klkrky0EbBF;4dkNa@AH}Dz3^t~5{Hntl0Qu#%TkuT8!h4=5x zm#7kuF$LHw@LM14VRn_b1cZv<)!I%JtJE>{@Mw%)f=4Y0=q)zL$k5}fE96?|*_01a z(oFIW-+yJHbQYWr-3ukobBo)I;H(<1g`V`p!4EW_pAi?eAbJ>)Z|NFO88#o?gvCkC z4O6|GIUC*KD(PV*b*F@!cOFokzw>o~rf#u5vQ^0eVqc!qtk3dR#f0M!(<2-w8f!6K zfLdkLG`J-~KFfDGx&t`w0StFO!IAsWBY2J~N`FON`D9Q5MTTQ1c_d^s zaBAX@6w%ZIRsg2@&~QgY@U0BP=^B9!%(_`IeC+klAojS*^QN)caWW=n2;XfiHF`e6 zPsJ7|k`VAUJ$b}Drxjfsyf^7UR^122dD-ZKRw1K1_zqwpoVjnvmqSf?oAP25QL5z=tvZ?IqSqu>|9J8i%QJg5nlXC4Kwg^k4tB`z_&i zJw@|s6sQCx#mZ&&S&thcug#!@5}H8LFF#z}lx)*6qKpcFD3P{b9kxt^18scr*lWpO z0D9kH)slAa5eQoCPFO!rvZJfXF@ImW!h;PmGmJjXpkLkcy_7sAwz#3kYa;NQsg#@% zvoaCCq;H>0)j{QPAB)*(Vhj36$3QN{_frh6yIHGV_!B`{(*ANPhM$9Gv=}EUo@HeT z_PNG-MbJl`6|GQK7x?W;B7O9uR_aCjayrq=DT2c(pej;s_uUlj&x@J&4u2!4`oRnO z;I^u*xclRjitp$HNl-s?ANb?v@Zfsp+C4`7%rxhF_*N@#3QcE|6?v2JK;CP<-aHBmpxVv>^gWMjEPvx@M?zZ z#8mw5F6?hUTHx4Zucy>zXn#*h+#mG&5bt+Wj2S{NrWliw;t?a0VLP(scs^kYWje&r z9VeRuPn8#o`$?qFvRuGNV1|PxBvJtYKs@3p}!= znUb&sWy(i&OAlmXO!0df@@2PQ<0UNW_@YcniRpgj^vpd$!&G0^Qzkt1PY*;3hgRs4lAqr|Nh{w&>{O3_=BscAA&-N^`*X7S-2&sH498j7!5IO z&HeV}RU9Pj5_MOAY5C+?IBFprjluM3!e2ZEv`r-oS|mnQ@#*rbsmSGE>ow;7X%9+P zNaGke#$*CM(c2$}1b-U7O$7;<2ZZB?R)k^o5SGNHqZmuUeI>fffhh3m+-8;{SKQ1x z**;XiSg!ar&r~R>7cJu5x$nL-ml7*o%0p?tU`~jLl{54~CXW?K6m4Ly8FJ@Cj-{2j zQyHc!-ln8~aJ#P1T6T{0E+bM-rz>6M)Hn{bl`$|MF72XP4}Vmx{lYG^cWZLs`wR92 z#{y?=T8al4vKZa;c;VV=!g; z2I*~`$_Ye;x_=YI^1MCq_fKHF^l-SqBLe1(&V=%aVIAxO=7&{ds#=x>Fqs%s+Qk!0 zz2g)LJU9vOqm_gdP{X3!qDW}aCLvK{z(ZrX=oLOoZOpt!1}o}d=nEn4)4c;6rMg7z zvGY1otjpbfI!u+>1*KYNtVfg2n{B4$wpP57TjhF86MySqHhX;(P|jLE6y|D!#n~jw z+E=-6P6G7^3ap23>=}SL=H;!-WDJ{wr&%ZQ_v8wLlR!8Q*r+0gh775&) z+GG^gP=6J}z7{)OxQD7t!jV3sa(_9o_bT^SRJ#tl zLp{1)1GBmt)!bQ~WLB~Nd#l*5PqG(yrV!4kvNLU=DYYA{q;Js`Y^gJoHin^2KdZh> zn*%nhI4B!ZO&uI6&tK0x1FEDGyONBr@JU`r-hX#g6YZ+?hB7$PiBf#L`sK9Eh}x`| zCUs;OCF-_h7(opHQz^2JV$m^rP+SXIA|0f}uojG$UQz)vSu9*1-bUq15=L6#>Z1XR z1DN7yXOoA7wPdBT#RDh7Yly(%wM{7=kXYaeKFy0Z;#nH8`y<*{EHPgLdLSdf=zJ~0 z<$o=jMPLCrt#^mq`(C#CANv6Gk3|?zb@-x|Py$F)YK)>J?*$n-2g{T*n>E*Iu%1c^ zhLz(sI?S5sqDrCABh+kY}uwtNvrTFd$&Qe#nThX|q92(=qx+Qvs} zVr+3>O?s&9nd8mrAa*&U+L*OY8DV4AvspLSH*L_onQXce^^LJiHuZ(A zll*!4V;L(2YB`L5eq7;yesBRRoF)1TZ>di@Vta3jx_aEGNo zp`EMm$+%5#Crq*cZsp#fCGVow?5bG1-LYMLnXU^d_kp`bc}K~xNpi0XWPht!>k^z= zT5vk``mPJzBO6RI(}qOQ@i?#{x*mtwzC4jOXFf?(SWQ7j*-FU~?Q^lwV9(_p=AC9_ zc&x7UG^1P&qlxQO2$_|gc5okw;XyG~1_Z5A+$-;f+4BX#4auDv?$Om^ff5dX`2KBd z)Jw|hxnGk~{g$AQxF&B<)_<}2Z_}a!t2(mU?^gt6OZ;`Z#8(9U?^YH2f+JQcV2`I` z9yhacO29|W>M|wnH$wIR>y^n8HT{{=-+kDA(hR(%wwTA@7 z!fa~Y)2tVRBb0jd7ko9d(JM!MiSTUBu%CU~N37 zxy|WKO0=!sVd~``VKT5=-1smhOhB88?wTm|3A4~=o_5OhEO1uRN-ieja`)|#vgWjA zcfoBed}_c)U^`+7;(xlN=FU?iO#YmJScIjO0u~wp2ZVRH!#t`txl_*>X z{on}OjNP@I7g+<~O;PE3{zyB1x<~V2LrAF{4^i&s^~xXH<2sR;;TmvJlo{q*3p=4z_oXWO4?6}X4JYQxX2Sby>aZE*7pZWlJwg+kbd zOMZQKC(8)E=nfGk1oJ{p=j*3Q&7?s=cO{KCd8I+Zr=I3Cs-G#18p=zSf1YOCE^~aY z#JU(>6hO*Nbm_|9_{Q#-Xfpd!olhe+xUQ2p(H59mmtH=B=? z*InO&zDIh!4;2ynu1uYOO+oXEJ$GG8&-eJWI7&M-KJ+2OXtY=<`mLAFO$s8!0_-WR z#m;ICL7;ct&1#0qN&|K`5rb)kdeQyn!L*rWxCULWw*GwIA7{v-Tn?&Y=ij9y)EW_=VNndqUyAIpN3+FAg%y=QSP>4_Q$2H)hk_hCyybG-D}ir|>1 zXWV$z4z060S;5U47pA}ZvEkLW4k}I1mK4+_<$tI}H$Pd|Tb>tVrJa;+0{5`bIc6@8 zYi9^Yy-G}ly;0kJ4TY?|TT3J$(PKHOhRxsI(dFAb&QjT-l(1Y>M}YjvLNt9jeVyHWmBORr!O>zrxYo7H zdWQk!$-%3f1W#YIY7u_%)#-yj!{7e`&RT&nWo~41baG{3Z3<;>WN%_>3NkVvFd%PY zY6>(rHIt(!Lw{UZZ(YX?ei!^B)Q1B17QQF5F9G_HwQ-O*ZlV+j(jt&0SypT(s1aDkmbiG1Wq=`;ZN4D-+nfPCO-=gr$ZXBSiGf8-1&`y9HzuVdS%de{k z>x~$c5#HgjjRrA0zdD5plycF+tQ$LoD6Cn%M9PKH4wu&=4qk*zo`MM+kcVAEjGA>l zqTi|UJ}#sN9bhIs7~{NLJq11taEChrzrs!#Uw>9lQ=W~#KL*wYSLAxX*) zR{PbPHSD(23dd^UfbrG6$xx|)u|k*%nOf-v2|Dm@tw7I&mUZdiVHdMltYt)$;Z_Ac z)8Qz=%$ScR(IMj?K<%eSKM!DoS`7g<34e?qluyCzOthog=(*b9c=kD}0B*si?!g97 zFYN*u3F?xTg8&;R6Wu2hO?*Tt>?kmxne6T|t)oM;8)TscE*yso8wcfstqSoa0#6LW zCsDwsj~3-Kwq8=}akuXmV`~qcG#UlzA43-g1!P7SU`A@NHn=`iF#QBfw1aiYG=D)f za_|5aq=_gb14!t*+IhhBy#9R2w66mT)QFm50J`IdwlZM}?4?BoXO?|9TJ97Uk{OV0 zv&QqDK_J8`1QE4}3pxx&WqU9Nh`Y)jkn?-v=#F7BEhDqz7&^D5!zuv9hU~AwK`GRk z*CP}k6=(ub@vf@Il9?k{GB5;X;(wvF>FYc#2s$>0E&Mr4G{%fjXnUY*G`iQ38TP03 z=bmY8wADjQh8{9cd&M?@)CctWknHFevZEiU^(Simjana4>mzFYE46+;?VCOyjU9US zxdC_UWsE?xho~g_O!(Jek>IbLnOTnkP-Fl_*2BGcP=nN95~#EqlnL}|yMN_ZC_Cv) z$a+4xyDQ!60;@vWIIflm_S{fYJEJl(k4M7D}~Sz6ij9cy9tt}1nB|F z3%qZNSW0U0JA8m)i^vismXhQ|#0qC95gEtU^eDc6dIUMw|0g}doPX$ZlmnQk)GRp4 z9z{hRIgpe%O6u$hy#XfDu4@S5l;b+ax{~4^&!)nVY@Z_@n4ce7j3}|6HoWKYIO#}9 zm;^W;AW`XAXpu0D{P!$*Lt7$C?SaG;`zF?lp59|X(MDIG9pC_kUjzx%84>zfS5EjG zC`HNmv}ysNW=PKn1%J@Lc-VUwPJ^nn;$nK2U=0-6$1(b-97Q|H^dby{u<71(+mVt6 zk~i9c+VwH__c3^3bQ};e;phP7Zdm+5ZL|gFMGxU~DO^e-wty$?Rwkru6d`MrZcYJO zw-Q@lbHYNbPJjxCZapTpBci*;(UIJ8QdHzWCPmCL3(hNJT7S!_3DU(Fi8K*H9e%$y z_Hdr!of*u(+6K}aYCXJp-UM=Y&aOV8)mGyl^t&HAx)cSKbj?A&4_kjDN z&=4e_Y{o_EJCj5DL}wKPL@Jhx^#BcS6nywVq8KF`ohZ zl1JrxaWb1X?|&vBa){u*KbeZR2q!@X@=TDy#-FG0N~)=pMzY{{uTt*T4)R_#gMJ$u z8KouuFv%Y3OvjwOI%uHAw>0Q<97HsClL0(avC@%o)Ps=fBU8+OS@JxCJ zmSa#)hI&|{<>nxRS#S5CW0o?YuVfCXckIY~VH^FX1AiAbdCw0|laLfn?>A_c=8iq=~c;2P;j9bgt zde8;aqkon_b=d*QU|Ap4;4nw^3 zLbbnRBOv$IwsxKbY_rJ`jAwMPL8eF1-3loDmD%|z z_1*7cLe+5}F&^NyD>BM#Mk7YJVMkWyHIfJ=P=A;b$4I{DlKg^5zP*Lsh-nY`<%C`y zi(rJpFo~J_pPFskkg!Ue{L#QaKnwdo44fS@Kc!D*7jMbSzUbNo)9OR&d(ib!>{yIh z;q&giefRq5HE?0CyEdC|zg@dP&SUEEZW|dd3#ZcIaeB!H6?L`L)l#dXR@d;sp|)L! z$$yb00w-M#SzLf_AEOY}r*DE2lAYs!1d9*QT0ao5_;HR9seoV5Ya zbQxrR(d^AaYI7azJ?RoS3FQis{Lm%)(|>|5-mSi0f~B1MMBaf(@f~##)avPQh_#Al zVKdMHRcV#84)|%PuO^06cV0n#eJkcMWqQ<=8q-~d)la%YVZQXVp;!rrr+s&GD}=PN z(><09wvlhu@(0xVWlNQlpwE&k5wpH$Jz6`8`OP-!U)|c^*kl)7Y4<^6LiV`P?|&n_ zZ@LsSf}VCM7S!SG)WD~)gy`;1=(aKpG4%P}sN9|XVKTpLWM0klQJ2Mjl@DW_am!*P zMio1)R#UPod@EDQWRViv&3`YchLOPx@X3~T)PaR(3_99SX(A@36c1>~mkqzh3;9Oz<(Uk(ze}AUNTcb!cd>a9dnBsj*F+WC)*N+;nE=w4bj&50k zp|XS&cnYnR>J@9V5^Z+Hf1Kx3x~bu&3V~Dj5>i3pM_>H{hA0P7Yg(=LB9+^ej;zk$ zDPHJ?bW8Ryl`wee9i#V6xiI#zmRV>k%iuTkAndp??f3RG@1P zc42~WfEC5cF4abDjPOH@^Rh-9&MKZx*d-0?X#gO6x|dJa3DRoYzh*gDr%S&Ol5E7(tAIB7=9-#(TZyzP4ig~lm1bYiM{FH0^ZhbG)>gT208N!GD zB|XD_R_|XQ4yd^LgMWZ^yKQuAQ@0J_-uV0nE9&Nc8z<;OUe+foWxLC>r%`HgQGWz{N5R?Tc~P&lbKu3z z8!%ni4@)WC!_j1OdB`N3yT49Dl;}iEC58n10L^v_4+PIJxddLM-um_fI%1G*m#k9x zFv#d;0mA$tVwz|YlT^j(Rj@9-vB|vI?#n%9F?Ux-tDFNC@mI(S2277`A2e7xU$F`Le>Z^p>; zV~lf0G0x%5W1PKNvfGCGsN5FP2BB^rf2S7#y>~xYIe$3?H^fVZ0Td=MGTLwm$OKGX z41z51X|K-5WWFOz4pjTw<89*COtNZiEucA<3>!o}mmXE4_gM~BoC5S|o&;|QW89^dV=zRtV@M$)F*!`L5aZ-0jGpCj&ByFzl22W=f@ME zVlTwnF@O9GLc!Sa)w-M@c%^*5?B4=dV{~s~3UTi)&MJ?q^RA4M&b40Eq&nt8AFzO) z0k8$%9d!(U{;$m5DFeb(O`%`qxV3A1iUb0At8S&E5VNzJjp=x|)Jz6tvQd`Be;JF~P zAAg_^J9T3gT`*aw<`0N;j+&p5o;QD&!5~mK=hH{r!Dgvje?8(RXYN?`Vj#8^^R)8@ zfj=H^Dr>d}{_K3bx-JAh4KXOhO+Sw*V)-i!&T}_*mJbJ|Q44S~S87~<+0P6dW=9T) z5)B+RZZL}!Gthh(4k5F)?O`}M2==Ia{(q-O$Z^+&%Je~Ui@8FKNz3b?VJ*!A(ud)_bB7@9TNsLsWVY@Js+VV3h7BABQgk!NX-ZkGKG0RBpa z8PNQ}&K8H)ca8nOFp$HM;BJ0=&Ld=5)A4?Eo(|`hPU`ROx(6u{W)P9dgfz74XCO!< z6bui|fx6O2-Y&|35=>pm!yaGl?ff17{Riwn%=eRCHyQ*qFgZDsd^bUV&00%y9Jdj^ z)A|v6oK0zApz%J&PAZSe!AWgSPAWx_5+#ciWinE%0!Nr`lvQmHhW0UAI* zzOTEnKklSZJ4t`azh_q`a`!v@dvWsPiArB~<)5>w-8aXRum7T8r;O0X!S49#Bu`U2 z4?C}<@slz{Kfd4?=ol zXxu>uC7k!u5g$cx&gcp7(OD67oW4WpLV_`V`m{gb-nF(NPX9y+7G>G#br!3fnXa4I zcPPLI;blazAqeFpeLiR_brZ;IIC_}=_=f5BS zNLn(xD53*rNK2qZ&@t?ee>yq->U-3Q6%v=!C;+u%RFq-*3STM@7U=v+02t|}oBhFx z0Mhf9@AhDY^;YAF55^jLJ-yl+VSuz#=SVsdJ%$+dbcI8W7CI`nJQI4Ec0$X4*ehXz z4uB>}(?ePv6(fRwB{Ni!qD_(g<#QbAf`|sz>i|A3*Rg1X(K<&mtO-&pTGCiF1JHrB zK(ohWI6w_+?dmCUdKZ4S2O!4*G+bTgG>wZ&*`jw7y&}sQV?=vNvv28L5DxeIufC6> zSg@MU&s(x4vdyvcl6dRTvXRNJYidAWCWpb1A}WiabUep@@cBgE1X4@O#P@^r1HWtU z#QuOQ3-sgP;|x$39ym?~e6)B7(86imd`s#uecY2<`r!CWcE;y<=MjKwj#Q(aaLP~T zZE+^x3Zn?Ll&b79P3qgcrGSzMe<{+St?;Z;MF0-{JYxCv_$)gYZjC!vCWsKv25MsH{uLO4=}npEN)Es#16 zs40hzV$ik)_|5bmoP<6DHsD)8iospINwa;z)%@lniw5mSV2&}RZ3puLRLW{wY(ieN z)~U1H_A_Lzn#xa3SEyRJ!8zI4k_N{n8ycTkuTw;a_{-v2*0RrRb2lWONX`!-wMe%R z%IAoGar3sL*9>QA5?Eq-ToVa=2AQwh=jP5Uu%L0>nR~3y4^G;!oE2V?KoB0O?|mD| zT={wtA4{)fzIsJoFA+a@)O5%@&0y}Gu(5&pjNPiXXrqAOto01dvw<-&I?Z}lJdmyj zM`z|09k2gDK8b#Yc^Bmf7^D~xZgqO)oz5hGp+Zm<h+8c_bT-!Zb3*l8R{Q z8bUg0`HJ~OR;e-Ecabv&!6h-EBXf!mZN=<+HiYh)8S9HB4u~Yl7N;Gu>mj5WfV7~XWoVO#Q)@f|rPT_J$8lHD7!@hJ+d|{9pJ|CB zk`q^)8j?YcYH*uAo(tg>B-w^3^QRuOEYz6epL6g+FL1LOl2Y8xD#>M{k2aM9_3<`8 zQjPnM{`O6Oyy}mqee6Yl`?5cZ{`gZL%OqU3$C2B5j7Qx!{A{3xMbIlOp~K97!Yg02 zjms(eS)hq1rua&f%Tr z5@~6~BhZYrx_eZ&~ez}9cGs~D*?%>~NNZpg z;*+7aNjn+pfjK8d(DP~vy&z-f5$idZ)R!2lqaMIk;ZHkql7}75b`*<$b|{Ehm)T<8 zLdaTB%lxvueMk?Xn4pE|cl(2*mZ4MAx20i(*~u@6e;XgNm|%|H1fRdB;sk z-!Z%$OEO*%MIx%&(lB$u(PNwR)R_lh78X+f?a`SB?HeO|*hT56L2DZ75!)I0=ILOz zAPEehPlRPQLN-G$-e$dA@jECE7~5F0~~icR1HhV zn{p&&HjeZn6HmyVbqu&QTiM6O+2YbJCs^sxjm$j|UxvHk)w7dZ=ln3p0h_ zmZ$;c?%p$|Cw0%ZwZs=d(;QcCMSpe!ShqKw+-Ox&_9TPw=vu6Qm;HLgIBa>Aom_K| zs1@@t>ELlQD}Re+8cfYuCG{U1uZfpQD~0zmX@z-ocgwzDO(kBNme%C3v)M;dKaoP# zX%>IAth0VIwJ6fh7kX6??MA6`)?K6M4Fh{p3U)X~rP2 zu=1GEP@S?tLMHX;A71`aexT!1^jk}^yiEVd%a_>)`6lzY&PKzQf8A!oq0Ov$>Dsi5 zwPz1~Z{XQZQzPQ%^KDX?)A#!}6%r;ccr|B;!xI;6mn*1$Mu3@sFt5=qAs*d4tlDy` z?UX!|6IIKWAJkk(kF`RQi~24fY?ED*sa;rWJy)q1;uaaP-{Osv+_$ZNOZ5{Ho{A6R zo>X2a_j#r5EFCTeNLOk;`T^M>APb7v&#q-@{#Ge#fSPZ_^i)(kmwpa_E+X6}Ul?4| zgZjei*C-r+fcoM6^?u7O@{Z_6^{=gLEyr|zQRt<;!@8Z#0E6P}Y}SaaZ~G(`7Cp!N zFyPl2(2x<2R8sgfO~N(rJdCBY-HR4FGxD$_o>FV#;y z=b>y#NtuwN4E(>lPNsv-O+Gf{&?vQO>e4+;O4O0!{&q9E0_y@^mu1%wJo^F95@oyv zR2)mUC>&e^!3pjz0}KrA?(PI9xVsJR1R31j-Q6L$6Wk%VLkJMy&$<7*@7;U8>eVyd zySH~$t*)wFJ8%L{v-<>`;n6%lMP{3vaL90KbyxPT5*iOCGMjzShnxD2jS|jqHtVn8 z5~d=?u?BPj!ntf%@}1F_wD>=r;}-;cf8nm`~W zvdC?I{BpMa{$9&maQ{G;AWfxXZ{r|jQ}R4hKk#?@SW@XXsS`399yWLl9~cYXwW5Kk1p?XoL*#O2jPQo!8qKL$ccW1DZ?AYPYFH-t84mN7W?H_gcHeK;FgQlFm@5ZcE^)?^<$#{SSn>Gn)B zY&gVSG$5XA*`1}nblPdxJM4pH(_botCoFK*a;&*1@doXehOqAZVIxOq~EshCLSHOkF~hd>XHPPzdwn~Y}}R@hmKr%t+Z1CxG^7-SPQ?-AJFdq=h*AID8si zeiBZi>%}zC5e>&86Fe+f{tcj=GyL|MZ$zSughrjRm`p25xG0D!8DA5rbcLm(2#S*v zA&-t^rj!yUAJ7b0P$v&9ML_StPR{FKwf@vK zl!tlQcyn>n+7#!QGuc`$gN)+`A3v5H~J}YV+k3z|ivFvWVs_S`zwl>YI zEtY|{Bt)eJ^$Qyide;(7%eJI#c=Vvj@B^r^Sbn~ z$D3RoCpw&Bojmo`0n7B%S+P*G8^x3+AE8|5n z&5XKHEj!06GE*pqEegZtAafz5IhCsb!>-bf{nrbu$$UBRD14^58Ps%LBA39;p5n{u z9rgT2BD77$6T;;@5|Dz2KK85gS-pf!7XRSD;vEhBE@Sa=3o^9N(175l`dEKDdUh60 zV1ir}+PYO}+S7!?AI}a9DuAvN{_x$&-;5BtLyHXK=o@bzcy@~kuhV!|u1jx>p#S6> zPIygO2r7$!A*!y0D5o7mj`9E_(~bSt#6M|3-pfTII@zhn%4BjLlXIY#W*%;j7RwFV ziP9d7g1uNgh!wU-4%x$C@R!b&d+~+|@^_ndnxo@7Y&r^EKwib%52G+xmp>j& z4Bv_%qQp$P-)E?2-wveO)?IaoWxjq$yi*hfqitrX?>un{e_bfaM(EO?aE}`)pjWG> zCwUt@5bF5GMPzxxm_AYA6XIOkzb4oSdqpyE`voLNF3a8)nV zee)w?6tY1=*~7+dUV6oO750(F0m=`ge!SLAH`@UN#0h2KZB7EqbKFG`0}m~BaS2_( z0EPupw#w#&Q}09eiv?0%a#$M`|gFO1lB~P^IV~)p^}0Hp9_!1Lk&`>eJ#W#&9F=srB$@hCXxVR27DhA z%H%vqnewx`eNX-@@uj9rWjD-Q9Gb*^FXiDE=^Z@O_C+xfzCZs8fGb?>?P(pP-}nvz z`MHxd4_#DO{Nj28H;LJhfqo*#C`Yku1dV5!7-Ou|N69Y2->(_oNb{SGi`#-j!n?CR zFs0=_=PN1zc9C8NF`ss-_4bM_>2YlQMy~_p zn20`F4YjOr4Uv)#O5wa2p`29^?$CuBIFaxnjA65VHJL7uI)*-#G{nte>e4;M$>U8*he77dHqQ3q#nou^=yx)(@^HUc|$ranUwNgghZg1UeaZCrZnW0*(7 zLJfAX(NNIYPmWVL_?~;7F~K9hSl2=z%=p!uAFWeFdP$~G zJyNIWONpD-mF_Q>S-cdeh+>-Twy>6->fY8glH3l zz}Vl8E^bkQRgn!V4Hi&q;AMk-i~WWUm}StXX1fSA0zlddMt_KvbtL+%y*m{#hEMf< zRwX`$vhHL)DU90^;XMNvxfOjXDK}c8w6n{SrVI6RE`r=n0#Yd z>EQCs7I3KGEkX)?XhL`tylhz%6p3`7(B3G0-PP(l-3w)`JBu0%lry$o74WrMVCGl= zj|35E*6HahX7_sj`Q1MA?b3DS{QP`$=GKTqZ9SM5S3%j|h+u*5 zy)^Y7*bX@*5Ud9>T8HeF?ly*{aJ|(pMJJnZ_^2V-uYWQOxM z5XaD*mPNq5i=wv}TpU%)I3d-Fu>b>anR7S4iS>eUT>OUHt=f;TD#XSVD2Y2VdsQ`o ze;qXGu{f-)cM;s}%u4)6emQ70!Jm?srZwqP;k`;mdQV7W{C9ZsP>b<~*9J|z{6Tp? zxx1O|l;7}X&LpTM(x)9QshG2$jOvT&76zhLS%G_bn7P3$MP`l=%&-%-cC{#Er;T=Wk5+ zL_^zI@1 zgdVmYYe0x0STVR8^x~ygjOhm0X7vg{aPcgz@%@BB;OVV5+GV-G@pvq|7@}LWL{5j_ zPDXg3cVck4j_-xYre!1K;6OfrffwSt@H=GD4@1@U_K!vqp5fpy5u)lS3g-s0OOm5L zy|tEzUoMW5sg2EZQFc~5`5MF}>0AHvx(6@Wh%=Hh7=TgYcemdCqf#V|;fRC6+2r)a z2FcfuO)Sw=ppZMRM4*_ZC@pON+R`?5`SlyK(dclY0;h&A0C`DRIXIIwxmP1{k=Bn( zq+EU~3B@(dxgW+m;0x~bQsTa8S8mR2@yi9@W88x}S!lSHt~6|_MQ8eX`V(w+C1Kv~ z3#)t|_+pqrHL!G+ImUz&c+-PcPq1Upua2-@+AMw}X!ootz2tyelOh`&Ts(ieGcs~| zDtQ?TOwZ~>Ghg1UsSNfIg;`I#x1-CL;J(~ylkO0xG)6y~k9P)EQ&jU;4|I|?uXLfe zEb&k?KW$(bnjdgN>;3$(pJQ_=Wg6wRO!?Lhj%LJPNKL_Ek+82mP8wdFUH}<8o&a-+ zSUB1M<);cQQ=C$?JOiLW7rRZ>1MvptFCCU|8IT{_@V7cvGeNSy&Ik-Jpb8Pn8#x2> z?e`1RPI%8l1o}=cl-?P|!vYY{=GYV*{A7FUlQv;C74ZKo4V3sWD#Mw$5>xYgh8Nz0 zsbZ&?Ch)H$j*U4B=0spZwIlLy0-ug|D7KH%f39^ZmY+Dh$-c% zhEYDW3-kfUsph~R;w)ZW)9X~Lk8fUe;NxVz(=^RWFu7JW-;a=D*Q6=~gi-ZcA~oKb z3*LP?x4a}5M=kmaoImektjes>`98{MS@mFKbat4QuZTJo zBsV{#BA^2>q)~OyD))icO843}Qc?(+F7F3Br8G!LcQqOV75?CCKyZ>iyTR%ZiKIW_ zjCXuLp-x|t=gq!Y2}3Za#+FdeqgV`MpJ=E^2M>?pIZ$>hO-N!o*744uyUOx8?}SXN z_9$oQD_>kf={Z}A!gk}ftR1=P@|h64=&_`>olnA&_)>vdeZ#+Bki?}tff*=lGMaldTdRl8L5eSgS!ScUC(cTN zKF%SNNjt6e&F-Kygw|&Q1-vmn3uQJJz@Xy4{y|mZV^AqU2|KRznWdxn(XI7tW=&&Y zYewBcvB+ztKh~p;M(j0dzA+#tBz)fs-lyq3RK($u#P|1Ae;ESdXX)T=Be!_>Zvq{X zkG^=QD&Wda&ICY?f*rENZp6(Gdl(P74YB7^&ngjLMCT*p=Aov>Qt-aIl!8pi$MD0% zI#A2OrC#vce!Q6s4zzbmt*^DvC)ytR|naFk0 zoEXvcviXSH6s_FA9I*41@sWT?&z3!c8G?)R0*CVp{_kNA{)HDT1}uqPJuiUoI)iPi!UPyF*EbErQj5QmNRJHnS0!B$a4O#urj$c zdR$ylX1&EIT|EJ1)HsKEHj>f7LL8ij&mSM6Jc8=+FWnmLdcY4`_Uxp&ehN^`7j9Ei zr*tUTV0ev479_RdpoLsXTYDW|Q7?H3buUXt6LnY2@ZQ&LjmQKmL~8AjR7rJ>qZHgD z%dO5TY|P};N_iFoz4bfgCxe+a8^6~v8SXxR62D0#I|;pP_nKJqA7WI|g;a_>HA^aA zT^f*Yl|L>>>w=3tACnAFSp1;nnOc?X_%kw<4L&ck1R5uQ?Ue#4m)`S`Z1=_gfc+(l zR+5#FY8NXf{Y_*J6{8nk!cJvf>sRab4s=cRjQwvi9jYUme(yP(R5C{FG_ftcgTam2 zZT+2VdfsToT)}yRyo-&QvK@f2v5?zQk3WB!u|Snj{S`RT^p$b`<7wa<3O*ccGD(q- zp{oc`ryNRCp$F@=Vxl&kYowXA3rs*Eu5~eJ$_C1OsuzDtXrBdwcJdmw@i4n zwKJ}y)rEogzcUg>MKQc)XAl07F=$16T=DVgbhq_bZ*sjc?p(;eNWHX{Ex`FP9!4Wk{4`pX6$F7Ur!&;6PdkYv?-S;<@RD;yI?h@f?MzKaA0%>b3%+RUVv7g>yc0kdf(7 z(f$ga;J8%mQ6YKj@A3#>S`u(`k;NAEk2!I$9{#B~KQmLa+O%cAIVq5forAp7*y!S- zjH5=VNsWU1?KbDt7V8Gi0zH?%yZx@g4MK1vii#ga((hpH@r>TWRKdi~MbAT@aF+}( zJ|1aHb0CE$ffvrepCFVd2`>>M`2<(!NYelYHdFy<`DjyZtgBcVMc|5t>A%r`t3l=o zAy78eQSj0@3A9$9Q+i5L#TOrUE0x9Pe#l|JWt|v#E)fANilwk_z@K zq7Tl|sgb``U-K%R$JLQgN`0w5JPbu>v$YJis*7>dlaPdGFkXBjP z?HJ`x1EZt&hmkTjZ1_5_FGFRWILL|pu-E6czFpukLZwk65$d#YS(WW)9$-F)K4VF~ zonIo&)z@$JPj21}dV@675w3xyWi`GDeDYKBQydWyAPf&@%>lv8 zZfDx2%9fuEuQZx)sPh+_)RSTo8!1%yO?%DnpdT(vd*<@X-xb69bQ!@CL2uj5h=xDF zse%s^mtb!n(^^5o?qOyo26C%jehi6U^v(~gxq)v-JAC(4qry2&=YY6ZTOR!ttfLn%O7v?i1#G~tte?sv~BZ0gs!mU zj_kH$9vUruvaj=RTXaN=pPyAW=T0hkLtmT3k%nNnVBvE9pV?|o5C_M9Z|C6Pf?Nl4 zK)`xf|2<K6bK}ZKt0zt=%x`+j=k@)0xfhqBBJ(3P zW+YW(3X=x`>mLVzkn#|E!|pc5i}4^Uc)SI;9ws7|vXW2wk{{n=Ii#1QO_kAUIaL)g z8gl$mq`y8`YLb9wWo&rZ>pG?`;P|7z;BIj0?;&`Ekf)(UQc;9XiQjgJ5eoPqPf5$; zox=evw%}BRAy{z-oHkcQ*V&Dpg@=KISl?Thr7xhm~t@$5FnzJ&bcvP;`>=%8lxepbY z^JtVw7DcToI1_b6m`U3FA`d0c%6{ek zNyOB}&uUB$TsV@UYA_N4;sWKLsVcA)s!J~;_Uvr!pl$teN+WAMGPf=m^*q+EsA>`& zPUu|)Unv`d+Bf{XAHzt*yv-hx9(`vk>p;sd7P-5A^UsPWFBf{#4#^LV;IpIcs|v=G77_Y5U+XI=uXot&u1r_=M40BEG6S5pAAM@X$o`iCreQ1$eu*r0E~1qQ1-}Hrc!0 zk~YOOe?TLGS(cnWwo?1*fQD50hs(z@UAaTFRc{+nle?;XfnC$vt*LlC@9)NF^OyK; zX6P{te$CQ(Mv+7OpYRF#beooKANY(x=L;>?_%_fN$YbqM-td`EU|-zTy~-ACmXo_m zg>5zLUu>zHdxx4TPt0sWP@ATe(?s*hA6BU~v1(#NVXqe_+zwDR?PMs#2XU)uI3E0} z-1h-Kl)^AY|U*T*EtLx&2?KuiE(?drfZydBGy*rrI4sUdKW%fZ(yv-Q?Pz}p>#Bk-vOBxTv+1Qf zG083(yXFK!YI}tt8TBKxxz@-8=DyUMWvp!j8oD>?GS~rJlu%Mlxz1z&qDL}Xv7^bd zRqJpw&|IVxNA8-O7xvV8owVHYnaiWgG4ohqSez!4E_gp?xZ%a>yzut!>n`EXX#~*q zx_;->*}m5Ne6C?VI3AYg&GD-DvQ2+vPjnU2H+J}yR}E1kzxW>V!|Cp8t?TC>IKFk) zuTupCJ)LQ!eZAl9nLh}au}Pf7_wCAI!sVFRBpmRwI*4-hkwwBTH$N(>1;DctLtKy; z=M-e*(BLRU7YMka}`Bv+86UwhXd#_}VWDryE2SjM}_Eg_) zt>4y0yk1p+2|X_<4rJSA%5!?5udJJsy$^7m0bt2N6x-_itoscZ_BUDrbRPvCB3U_f zV3?1V7wV9}7ICBwlOI2{%=G1^%GU&PHPE>jBx{ilbMQw^s?VS|Vnx*I=cNKcH0IeN zA&t&uvrQc^HbI_Sqnn=yMWi_NLOvHUQKy^U7SFjux^Q z-D<_S$jdy$ad8M9eNyG+Q!AZPy)|7U1@qV{ELph((uZw0e+CECguSwkS_L=T0Lec= z+uZjL9DWJ-T2$pnppe(jot~(-KB6n}{mXU2`mmkpdPzfZe5GS+-%$mX0Ox4UlyBi^?)?--f`gUrd1A)^-S&MTCU}!D zZW}ayKbFS=UjmCtqeDx4jm$`3`jc3%klCGerZ6${*Zi3!?sH(ZfNS2bPk>ZKrM{N7 zN1~(8{!k++(mD-Du101Xo#wR7-oA2(TX&`3BP8ZklpI^j1;5;Kr{B-Dv;5MZ)bJi# z3pOm@LfbUZ57*O z$nMwge`6ibhW_NVh}hagwac)m6@+ltY-S%+XC2tFG;I14E6_YTCpPi5?1NF^EXg<7 z*a+o`uEa2xr7=Oo6MNtHs6)vACL_i45Rw?HT%*y0J?Q!pu?{^8gX^_F2b&k_NkS4$ zYhrjFJhFRZ$)Xz}S%_pQ5Z?RUV|C86&p%OQ+2E6&LP|4rb|dPPKc!xW@KHKbgAff z&XXsZ#TIes_Q)$qcU&3@bEnM|I}Eb<%_jmb8u3w6)kKh_H#EmxqYoH%I0w((|IXlS z2q&n7*G*H4F~gH_hDmgDTA+@4i zG^)-%Qqi%ZXX83OW5xE|?&1&aA-iC{EL|W89v_wxEvoZ*1;+^Ku@oGkP@;~qPLo+8 zg)8<^2s>3aPHb{sz4FDEAoCar%)o<|i_$N-Gxr%t+n-pX)PI1NB@YkVQ(G^Jedg{f znFyq;SGpZs9`cr4tnKs}#Mv-Prhc-^85T*Pq8;X1;M}brHO1 z<{i@7Ymk-IRq_yde4gssa9sKF?13Fy(ulQdCDB}CpDB@|rLEG4lEw$%=Thx-a%o}` z;N%)WPs8xCbrAfpxgH*7eL;V2xD^oeX{IT#xbNxx z^B}$QYf)53Ivbp$L_*oUrwQmi9tsGnNLe4HS*KT@Ihk)s?BkG#H(>FRL}{i~gDI!a z(rur!a3ec!%=$ycKZ7vNKV*K9R1`*m-$+q?FP@f zTtp@rog?GF&%7r0u6CJDwErTKv>~6zYa$sQDMIyBEzz>@<&U;GtAcp_F?BSuRat;& zBe|g=ilmXh@TU6j?shh{YsA$B>|ZK}OAC(4PZ)CcySqeh6IT&^LeCK_7{WYF_hbds z)U(JR!G!Mc7zv5rceGG*AH|V}>pEt1HRJx`;Vc5yWua8|5Z$-2yixLVnfZ(cbUPz{?jv z^Nq>WaO1{}rALPAS>WBSKfRTf_<6Y^j&Qdjc+J3{C)~3u+!F2mb2I`<;JbBYB30{? z2KSk()I;)6Hm7TtOCUq14vk;R@RiwFfdWSU?P!^_OH%WQNyXV|NQA;?LsO3`hEt~J z=W}Gt4Y^~UtG>OrAJprA;s%huqev+kN|0vW96a!3DI$#rv8d*|5m$}RTB~ui?Hn36 zgL{}sF{LQoa{y+y3F%st=5Q5a<#?E%PXQnh>lD(sNh$ z(_Al`QbKrO9QSco7St+b9X%BO3Ronqx928wjZ^M<@rX;9T7Uy(#WqZD{gPu`n_Fck z?V&TM^mnv7ebTySDpSYIE$p?*L21xmz9qGS+Zjy;+H_fMuT2C=&3Iki0 zF!bYNBz(eazSSPOnJ~=ho{?E!A91UUEk{L<7P=~b4A-sL%`G-S;S zg&mFa$BXhn{75eIW3QnKI`P+`FbQ}YS2c##P4+NMq}Fym&&PxcPnZ*1f4>5@PmtX4 zX^@sUKx1wh)gYi8C)ZI08h;rPd&;pICWh`A%Z(O)=p()SpAVH~SxUHfSaWvnHWDY7 zE*;Bv;rQC6O4u7dkQOrBy}87L1iw{ePseDCiS7Ic*ELh@%Nk$zwfFgJ|O zc!4qyl`=fb%+CS?Tja-&sy{5~l0j0-1!bCZ6D}rAD9LrYeimr>WM_Njf4VrrbsuPU zQFl+VBgp(VG5s1G!<_AUpjF9OcsK=M(EI&}errE_JT&JlUhA%)bvAVZYwsW6{C-6< zis^2W^|J}8;3#P>9V?zHD5HRz*L00F$VSO`B4(=-idwJabGRx24zeaUorQuV`;k7{ zv(DeH9%;SiGe^We1&^V8dL0y_qCZ5HTtV){ca5wG?-sSeE;6WG{m@^hNqXPGNfC&# zNnPL%?Y0lnkzg((B=FLU=@F(}LD%f8R-O*V64}@txX_5j7(sjrGphxE#xuAQ=ylz7 z4wO%o3RvmCmODu?;TGGvDn^?1PLy*L7E~0J!hbrp?0RI`xff8!mU-^)IuiTGp5MTF3hFyUIqTu`E5q@qa)*+1Ur|5pe zv3Pt<1Tv=&i6e^co0UmdOm@IZNMxi5NndD*f5qz~ozv?R)mjYyA)uo<3sLIWLw$c74&~ny6j-Dg-E57+yC2Ua)y=KKD04WQ4T?S2(|w>On?u z#-B{B)GD|U^O~a|fT@XwLVA4#pwT~DQFGHVFW~+L;oA$C4u#51rCwG*s+-&PIqW!j zXIS0~+wbQ_kHO1CJ1Q`pSTQcW+4z-UJ1p3+X-k}iCrcQpw*D#6$IfQhj^YhoZ$sVS zrMbq2>63)XIwvleyNXjngsG@9nSlDsV$T><=Z&|ylho}J34+{rGb5JWUES+Tszt4V zYt|2T_V2^wAVEC?*y6mIX%>HoZ;Pf1xfPnsX>r54$0fhAj=7!fYK!3tzbw{|`X^++ zsA~oY4J%wCnU$PuiSw9xc=^nHNP_q`O5638rIq?Gox%_>Y-XPt9{mR&DA%>u8YRHl z&IvNX%%M#x^O7y}Z8Sr-hL*&9wT2qK5hchByPpfN{3G|xrW%}6;N_N6Ko|Lmh1t%f z2;jC^!&d@=&{XMk8b~XlOV57)kw_Tv)$`9nKto{+@K32l()+emiP1YIOybofo%XwT zgV)o$JQpAMEN@^G{S05Jn?HQqVNDJ_@5I*u*WfpTj*n%&TSwR4>1&Lu%X!O>rEOGS z&ItS`Sh*5!9~!DL)V2_b9$=t>mh!ysd32ZT3QDX>GL%M7*x?RJAi?tWL#8N+BoDi=Lyo)ozSQ}YL(G*2k+OMi8%*oVDd~+sxUo+pfCY>%V#+ZT_fB=FX}4A zQiU(rH|eRR^5u)xBEx28l?^Dh24eTCX}G;RA){qw^P?k)16f_Z{YOkUdGTjRDo_kq zg}MjhIeq36$1KIZ^c}CNF&lAp@3sb>%^Mp(jc_@)#l1koU7(Jk0gv=;IB?^oR4OJZ z*fBI+rDvaOdMXQgoI)7aR zki>=EqE4+2S85|%`IDiCcg+<#?WMD{?QilwtVe40^KW9<1NeL+38kT4&0Rk!z$UYG z$cy`{skoh*ix-7Q$NLBiUsmMULfs2i`G(j0B?Ul#OBL(}$cswG`6M3h!0 zbI!!s~BL|cU$>iV1jo?D9n7p$19=U`roI@Sj!k{z`pSp{EOK)#zxjP zx!ff(Jltd@?6+G$@H!R#)L_xK=79vX!d1?>w!5Sh!6vk$<;1)rs^ap{en!Eio_<`N ztr2S^)w@kQK9+B`B!$BkX5fX(9Z0h#HhAXm&;;|!jp_8{7F*4x8xj-@=59*lVmRZF zW)}Bj-C!M8`TEro>50SK$;xK$XE15i!~?LH5J*)ti7Ty?xC`S7U4(aZ`jJORUqohM z?#vON>FgF$7W(0>E+gShbR)qgMkxktw8%?QFcC+U1N?MDcA?={UfjSwhnYx}Rc}B4 zq%uUqHUkz{UCk6S&{>EDNAxVy#e~l8Aq2e$Mc5}!I~&?Z)uL+sNzmCD2DZq_%_o9) z%E&#W;U&GX9)(*HXM9sLmcsrt(rwOGe8DPZh1LxNu z)J)A6s!3XXFHCY8bzt&-g%cG`to(6ttua(GBqb$DFJSnXy~_hWnIFz!G#S`0927mw z3CtfayG~Os{!M=8tA&9}TqB>p-!4jXhw7XweT|B&gczq4dPUf^sD*)*S%w<-h^l^$ z5|@evd*d9yf1Nh~`jb5xQkHit4qk!+>y#~@^W6RPVWo*!9fCJOtB0&e%TsD%EJSh+ zS(q^Iiv7mA!qAKSV1kPwT}35{Wg1aG#BIXQ7MLb2kIRPH? zTbF0OwE0?L)9S@#{l~ z$KU#!WBPQ+rCfaWj3cq$cc(DYG$+2g5vdLZQe~FCLyj?mR9i1WZ4|;^LWPCq{F}FU zL{OE_{CUioD4~xmY=9Z2R$48_=xCO>0uxRetK3zdcq39ON?S5I1cHu&6l-wZlKAnp zEZ>mgT=GR{X!`eO4zOp^vN}IW@9#k-@qCQ99;tnvF48L#N+Ye}F1{8yFveQ`XBLqA zl837%Nhq$RQu+EaJ~Y%Pa$H^ji*`K+6%UcPqJZ~TOomdM8pyd98P%e!eohTYhvUGe z;ht9kx7BpDW@|~x&lvMdc=vEKLU=x$Cy8!!3cqkIMI0ue9L(u$N0a-_4{$dvZ?x5a z)l$f^_>Ifm|JOw8mS;&as6<4O9&i|Ma~R$>zoJqF_k<=o(MEwmlP6ZSiI_s#%0E=d zcF6IuH-PpHh$S;S$|AlZzt&ZSnyp#6zmHq15(bUM+f7ov!`#$AfLrinn0~ga1=uYQ zvji0&JE%|}gDbFz9bC^yFY4s<_Yrc1p>tAq!nd)Ja@gC&*yZ16;bh9*dET>yD)y@iA zF8LhklB1o(lOy3WdMzIGM5HLA7M_~K=$%&(GQW-BS&IoGMut>RR)mXKG7&ueKCjN0 zj3y*#w`*QECa(&Ym#(*rT3|K`W>C{`;@#a0E`20!>@1DbkAi4wg8uJf8A32hE4O4Mn>UcLC-m3(SODiHO0YA9~(5FE0zno zM0P-xrKaRz6M#ULM&%JU)?)QLbv~+0srW+nq<==OSV1vK3%E&_pPlhi6Y)9C9`?oV}(8) z`Ewe*ygwy>k5v^l$7)`&kvPiQpJVh;ehI#^17}(uE^$kk7G0_;b;U>sxT$G0M-OX76V8%`d4v_?1 z7##wE+D)=Jfe++)Jn2rFhVe@YY7j5pPWloR15B;f_Mmiw@jc_RAZUc7wc9Avk4A7m zS-df>tKj<2uH`NV;)op=#+nL{;-tmDfRpo*2R`UkI@9f8YSgnWjV;Cg)a483>B>o7 zSdMBCU$6C&RP4SB9i=ysbVlcL8EZ7!v79$7UEqrcoGIzuK8{c3Y-yugf*l z&Nv^-5h%Igm61AkdGSNSgd=QM42hRhe&v^aqv76jhe@nr_?MHef2yGe?Gz;UpT z)PpRT1et(UnGCpM@oQ1TMu}e)-)!L7aN1dL%qYCV$;8jST{~HX;1}arp5@naoyNoy zk_*?I1%%&<)+_)nio9Q1aZHSbj*Yrsgjun_rjE~6{%(zYDwnjQ#|{|NRvt#(WWbc< z%n#ALHKZ^MPe_LovmnPOd$d+E2JgnoWy5Fkg;N=1t$6Gk5z=jvSKb$&Tnj>yk_wKl zD?Pi^mFM2ovg|bphun})bEEIJ@0+*o9JCKKpNfz*0tr;plhmtaH}p-if7UWZx{Ue8{5*=vN+?uD&?PN=qvEk4(9Dn&dD&f9Wmy_It%z0y09yH z5cezJC#9Dh9O9-$U#BrycmJqgzaG}92joV_qgbolJml0DYHm0Cm_DxTv9=cRR#aA0 ztW)fMy0R29w}<;VG<^N!iw}+!b53CmYfUrX9x;3?t9(cboj|dVIsY)?p8v#-zqWoqDyUQ!{sBf)S#4;g^y<= zV_QZ?KMHbcZ-=ihiosBAKHK9uN84?5x#u0VXnI=vQ}C7<;f{bQ#SU&N4`&iF$5fBy zsuyUpMfn?mFLm%Lg^4{o^@HB-=9bFbS6-o^aN54|C@ex*$ADFDti@lQ4(&tcoS{xz zX*c0&?_*A_AA&8kkk=5VL;%ev02Bv`Cdr+Rjz8rt>PGm&*DSnmo9zDRc=+{Sx6RN4 zdU-x4oXX9zu07*9Hr|3wmLAXv`G)9sgXSCRn52R6OLg!mmCLlIaRCQ(kG4CC!bwh* zjcP>C*dVI1so@4R0F@I`{W@hyAf0x&c9%=@WI+12NtwG{Gv|uw--u|@XMAN?(F}!t z&a!a=)eOE-{yq^yH`OoXYhWb`*gSI+wP~KTdYwCe3-9>fpYXv%(n~xnhLzQlUq%}r zQTZ)C30$>s-vBBN4cn@*ob8%%6duNKB|6aVd9n`obFlpS{=CL)Z%FWI!dCC!uv8_| zAX2?131(i8l@^=)^51hq#v9{x#Eq2-u3=gqpi*TgVnQ=-|5?CjP90jJr_7>gp|Yrc zj??MD`vux_pNf+=q`6s4?z2Y*Jg|^}jkcDILZV$JY{wo!;i8ZV-QzQ z>SHTzEWwf%k2O%_4_L-x{#ezH5g8IP6#kf0sZg) z-yo&`{}+G^NKB`OG^V}6%Sx;3Xv;!c(lueYIXEC6GmIhD8K@A?3`GhM2NxM9Cl?v$ zZ(>>yC*Z$MHUK;KUpD{TaN4l*uaSuHHA8s{=!px`xB6x1~pA@kXKs6ZY7*+1t$ z2ZSf51`5!4niB;5--uNG|4fR;CWN4)%~A z1$zIj9;mRI>8}`82Uasy9acwUXLEaJtFM->tct8+tQHP#&a95C=B&D`O043n7FO=& z5V#^5DAh)WA|5FCf9_euAy&n4|E=I#aU`-ms{*U{Uw&e&khBsW7zcav#@P~WC@L-h z8ygP?J109mGOL1vnYgj5Ih{B!I{*Lz{NG0q`LZZs5Ri+D4De4OvnNCTuL~fMla1$J zFg6ee_rLMjxVYKaA-LsKU?30szX^cAzgwRF#RSOC4*WM0AO{aO=-+s3-2WjA$ic<= zA2Qg0Y;1pN|7O_zAKG)UbNz>40QWyxiT^48&q{U>&ws!G9KgTz;$L`wqv8Gy1F-#1 zL;jHu0I-2L*?|8-WaHxD{5K2$T0J``=#R z;Aa014{~sG{6{MQ0@(iPe*TvXAR7lR+rQr(kPXBGg2-0!3yP~oSK5_ej9FEF-LpUv mlc%Tq4~PM>pdhk~tFg1Ir?a^QG7$K;r$VNtmQa#J{{H}6W~{IP delta 31499 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%0AcEWqTJ{O^b+)R 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%0A*=a(j;S#%yV`cLiKq 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 # @author Razvan Musaloiu-E. +############################################################################### +# TinyOS 2 Python Serial Module +############################################################################### + class Serial: HDLC_FLAG_BYTE = 0x7e HDLC_CTLESC_BYTE = 0x7d @@ -36,12 +40,28 @@ class Serial: SERIAL_PROTO_PACKET_ACK = 68 SERIAL_PROTO_PACKET_NOACK = 69 SERIAL_PROTO_PACKET_UNKNOWN = 255 - - __s = None # An instance of serial.Serial object + + __s = None # An instance of serial.Serial object __debug = False # Debug mode + __baud_rate = {} + def __init__(self, port, baudrate): - self.__s = serial.Serial(port, baudrate, rtscts=0, timeout=0.5) + __baud_rate = {'telos': 115200, 'telosb': 115200, + 'tmote': 115200, 'micaz': 57600, + 'mica2': 57600, 'mica2dot': 19200, + 'eyes': 115200, 'intelmote2': 115200} + + # Converts baud rate from platform name to value, if necessary + try: + int(baudrate) + except: + baudrate = __baud_rate.get(baudrate) + + if not baudrate == None: + self.__s = serial.Serial(port, baudrate, rtscts=0, timeout=0.5) + else: + raise ValueError, 'Invalid baud rate' def __format_packet(self, packet): return " ".join(["%02x" % p for p in packet]) + " | " + \ @@ -186,9 +206,10 @@ class Serial: print "Failed to send the packet!" else: print "Timeout waiting for ACK... Retry" - + return False + # Sets whether debugging message will in this module will be printed def set_debug(self, debug): self.__debug = debug diff --git a/tools/tinyos/misc/tos-deluge b/tools/tinyos/misc/tos-deluge index 813ae73e..88e132b0 100755 --- a/tools/tinyos/misc/tos-deluge +++ b/tools/tinyos/misc/tos-deluge @@ -28,7 +28,7 @@ # # A command line utility to interact with nodes via a direct serial connection. # For the usage menu, please run this tool without any arguments. For example, -# "./tos-deluge.py" +# "./tos-deluge" ############################################################################### import sys, os, stat, struct, subprocess @@ -57,8 +57,9 @@ ERROR_SUCCESS = 0 # T2-compatible ERROR_FAIL = 1 # T2-compatible # Deluge-specific parameters +DELUGE_PLATFORMS = ["telosb", "micaz"] # Currently supported platforms DELUGE_MAX_PAGES = 128 -DELUGE_METADATA_OFFSET = 0 +DELUGE_METADATA_OFFSET = 0 # Location offset in the image DELUGE_METADATA_SIZE = 16 DELUGE_IDENT_OFFSET = 16 + (2 * DELUGE_MAX_PAGES) DELUGE_IDENT_SIZE = 16 + 16 + 16 + 16 + 4 + 4 + 4 + 4 # Metadata size in binary @@ -374,49 +375,57 @@ def op_reset(s, img_num): return True def print_usage(): - print "Usage: %s <-p|-i|-r|-d|-e|-s> image_number [options]" % sys.argv[0] + print "Usage: %s <-p|-i|-r|-d|-e|-s> image_number [options]" % sys.argv[0] + print " \n Either the platform name or the baud rate value" + print " -------------------" + print " | micaz | 57600 |" + print " ---------+---------" + print " | telosb | 115200 |" + print " -------------------" + print "" print " -p --ping\n Provide status of the image in the external flash" print " -i --inject\n Inject a compiled TinyOS application" - print " [options]: " + print " [options]: tos_image.xml file path" print " -r --reboot\n Reboot and reprogram the directly-connected mote" print " -d --dissemination\n Disseminate the image in the external flash to the network" print " -e --erase\n Erase an image in the external flash" print " -s --reset\n Reset the versioning information for a given image" # ======== MAIN ======== # -num_req_arg = 4 # Minimum number of required arguments for this script +num_req_arg = 5 # Minimum number of required arguments for this script if len(sys.argv) >= num_req_arg: + # Checks for valid image number format try: - sys.argv[3] = int(sys.argv[3]) + sys.argv[4] = int(sys.argv[4]) except: - print "ERROR: Volume ID is not valid" + print "ERROR: Image number is not valid" os._exit(-1) # Initializes serial port communication try: - s = tinyos.Serial(sys.argv[1], 115200) - s.set_debug(False) # Disables debug msg + s = tinyos.Serial(sys.argv[1], sys.argv[2]) + s.set_debug(False) except: - print "ERROR: Unable to initialize serial port connection" + print "ERROR: Unable to initialize serial port connection to", sys.argv[1] os._exit(-1) - if sys.argv[2] in ["-p", "--ping"]: + if sys.argv[3] in ["-p", "--ping"]: print "Pinging node ..." - op_ping(s, sys.argv[3]) - elif sys.argv[2] in ["-i", "--inject"] and len(sys.argv) == (num_req_arg + 1): + op_ping(s, sys.argv[4]) + elif sys.argv[3] in ["-i", "--inject"] and len(sys.argv) == (num_req_arg + 1): print "Pinging node ..." - op_inject(s, sys.argv[3], sys.argv[4]) - elif sys.argv[2] in ["-r", "--reboot"]: - if op_reprog(s, sys.argv[3]): + op_inject(s, sys.argv[4], sys.argv[5]) + elif sys.argv[3] in ["-r", "--reboot"]: + if op_reprog(s, sys.argv[4]): print "Command sent" - elif sys.argv[2] in ["-d", "--dissemination"]: - if op_diss(s, sys.argv[3]): + elif sys.argv[3] in ["-d", "--dissemination"]: + if op_diss(s, sys.argv[4]): print "Command sent" - elif sys.argv[2] in ["-e", "--erase"]: - if op_erase(s, sys.argv[3]): - print "Image number %d erased" % sys.argv[3] - elif sys.argv[2] in ["-s", "--reset"]: - if op_reset(s, sys.argv[3]): + elif sys.argv[3] in ["-e", "--erase"]: + if op_erase(s, sys.argv[4]): + print "Image number %d erased" % sys.argv[4] + elif sys.argv[3] in ["-s", "--reset"]: + if op_reset(s, sys.argv[4]): print "Successfully reset image versioning information" else: print_usage() diff --git a/tos/lib/TOSBoot/TOSBootM.nc b/tos/lib/TOSBoot/TOSBootM.nc index b5098a1a..8b4eba70 100644 --- a/tos/lib/TOSBoot/TOSBootM.nc +++ b/tos/lib/TOSBoot/TOSBootM.nc @@ -136,12 +136,19 @@ implementation { secLength = extFlashReadAddr(); curAddr = curAddr + 8; - // check that the image starts on the correct boundary +#if defined(PLATFORM_TELOSB) if (intAddr != TOSBOOT_END) { +#elif defined(PLATFORM_MICAZ) + if (intAddr != 0) { +#else + #error "Target platform is not currently supported by Deluge T2" +#endif call ExtFlash.stopRead(); return R_INVALID_IMAGE_ERROR; } - + + call ExtFlash.stopRead(); // MIKE_LIANG + while ( secLength ) { pageAddr = newPageAddr = intAddr / TOSBOOT_INT_PAGE_SIZE; @@ -151,8 +158,10 @@ implementation { do { // check if secLength is all ones - if ( secLength == 0xffffffff ) + if ( secLength == 0xffffffff ) { + call ExtFlash.stopRead(); // MIKE_LIANG return FAIL; + } buf[(uint16_t)intAddr % TOSBOOT_INT_PAGE_SIZE] = call ExtFlash.readByte(); intAddr++; curAddr++; @@ -173,9 +182,9 @@ implementation { // write out page if (call ProgFlash.write(pageAddr*TOSBOOT_INT_PAGE_SIZE, buf, - TOSBOOT_INT_PAGE_SIZE) == FAIL) + TOSBOOT_INT_PAGE_SIZE) == FAIL) { return R_PROGRAMMING_ERROR; - + } } return R_SUCCESS; @@ -200,7 +209,7 @@ implementation { startupLeds(); runApp(); } - + // get current value of counter call IntFlash.read((uint8_t*)TOSBOOT_ARGS_ADDR, &args, sizeof(args)); @@ -213,8 +222,9 @@ implementation { // if the golden image is invalid, forget about reprogramming // if an error happened during reprogramming, reboot and try again // not much else we can do :-/ - if (programImage(TOSBOOT_GOLDEN_IMG_ADDR) == R_PROGRAMMING_ERROR) + if (programImage(TOSBOOT_GOLDEN_IMG_ADDR) == R_PROGRAMMING_ERROR) { call Hardware.reboot(); + } } else { // update gesture counter diff --git a/tos/lib/net/Deluge/DelugeC.nc b/tos/lib/net/Deluge/DelugeC.nc index 957f98c0..f27d9070 100644 --- a/tos/lib/net/Deluge/DelugeC.nc +++ b/tos/lib/net/Deluge/DelugeC.nc @@ -39,10 +39,10 @@ implementation DelugeP.ReprogNotify -> FlashVolumeManagerC; FlashVolumeManagerC.BlockRead[0] -> DelugeStorageC.BlockRead[0]; FlashVolumeManagerC.BlockWrite[0] -> DelugeStorageC.BlockWrite[0]; - FlashVolumeManagerC.StorageMap[0] -> DelugeStorageC.StorageMap[0]; + FlashVolumeManagerC.DelugeStorage[0] -> DelugeStorageC.DelugeStorage[0]; FlashVolumeManagerC.BlockRead[1] -> DelugeStorageC.BlockRead[1]; FlashVolumeManagerC.BlockWrite[1] -> DelugeStorageC.BlockWrite[1]; - FlashVolumeManagerC.StorageMap[1] -> DelugeStorageC.StorageMap[1]; + FlashVolumeManagerC.DelugeStorage[1] -> DelugeStorageC.DelugeStorage[1]; #endif components ObjectTransferC; diff --git a/tos/lib/net/Deluge/DelugePageTransfer.h b/tos/lib/net/Deluge/DelugePageTransfer.h index 6654f732..44455b56 100644 --- a/tos/lib/net/Deluge/DelugePageTransfer.h +++ b/tos/lib/net/Deluge/DelugePageTransfer.h @@ -31,7 +31,14 @@ #ifndef DELUGEPAGETRANSFER_H #define DELUGEPAGETRANSFER_H -#include "extra/telosb/TOSBoot_platform.h" +#if defined(PLATFORM_TELOSB) + #include "extra/telosb/TOSBoot_platform.h" +#elif defined(PLATFORM_MICAZ) + #include "extra/micaz/TOSBoot_platform.h" +#else + #error "Target platform is not currently supported by Deluge T2" +#endif + #include #define AM_DELUGEADVMSG 161 diff --git a/tos/lib/net/Deluge/DelugeStorage.nc b/tos/lib/net/Deluge/DelugeStorage.nc new file mode 100644 index 00000000..15f1ed01 --- /dev/null +++ b/tos/lib/net/Deluge/DelugeStorage.nc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2005-2006 Arch Rock Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * - Neither the name of the Arch Rock Corporation 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 + * ARCHED ROCK OR ITS 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 + */ + +/** + * An abstraction to map volume addresses to physical addresses. + * + * @author Jonathan Hui + * @version $Revision$ $Date$ + */ + +/** + * The same as StorageMap interface for STM25P. + * + * @author Chieh-Jan Mike Liang + * @author Razvan Musaloiu-E. + */ + +interface DelugeStorage { + + /** + * Get the physical address of a volume address. + * + * @param addr the volume addres. + * @return the physical address. + */ + command storage_addr_t getPhysicalAddress(storage_addr_t addr); +} diff --git a/tos/lib/net/Deluge/DelugeStorageC.nc b/tos/lib/net/Deluge/DelugeStorageC.nc index 31f76351..f5adb54f 100644 --- a/tos/lib/net/Deluge/DelugeStorageC.nc +++ b/tos/lib/net/Deluge/DelugeStorageC.nc @@ -31,7 +31,7 @@ configuration DelugeStorageC provides { interface BlockRead[uint8_t img_num]; interface BlockWrite[uint8_t img_num]; - interface StorageMap[uint8_t img_num]; + interface DelugeStorage[uint8_t img_num]; interface DelugeMetadata; interface Notify; @@ -40,22 +40,34 @@ configuration DelugeStorageC implementation { - components new BlockStorageC(VOLUME_DELUGE0) as BlockStorageC_0; - components new BlockStorageC(VOLUME_DELUGE1) as BlockStorageC_1; components DelugeStorageP; - BlockRead[0] = DelugeStorageP.BlockRead[0]; - BlockWrite[0] = DelugeStorageP.BlockWrite[0]; - StorageMap[0] = BlockStorageC_0; - BlockRead[1] = DelugeStorageP.BlockRead[1]; - BlockWrite[1] = DelugeStorageP.BlockWrite[1]; - StorageMap[1] = BlockStorageC_1; + BlockRead[VOLUME_DELUGE0] = DelugeStorageP.BlockRead[VOLUME_DELUGE0]; + BlockWrite[VOLUME_DELUGE0] = DelugeStorageP.BlockWrite[VOLUME_DELUGE0]; + BlockRead[VOLUME_DELUGE1] = DelugeStorageP.BlockRead[VOLUME_DELUGE1]; + BlockWrite[VOLUME_DELUGE1] = DelugeStorageP.BlockWrite[VOLUME_DELUGE1]; DelugeMetadata = DelugeStorageP.DelugeMetadata; + + components new BlockStorageC(VOLUME_DELUGE0) as BlockStorageC_0; + components new BlockStorageC(VOLUME_DELUGE1) as BlockStorageC_1; + DelugeStorageP.SubBlockRead[VOLUME_DELUGE0] -> BlockStorageC_0; + DelugeStorageP.SubBlockWrite[VOLUME_DELUGE0] -> BlockStorageC_0; + DelugeStorageP.SubBlockRead[VOLUME_DELUGE1] -> BlockStorageC_1; + DelugeStorageP.SubBlockWrite[VOLUME_DELUGE1] -> BlockStorageC_1; + +#if defined(PLATFORM_TELOSB) + DelugeStorageP.StorageMap[VOLUME_DELUGE0] -> BlockStorageC_0; + DelugeStorageP.StorageMap[VOLUME_DELUGE1] -> BlockStorageC_1; +#elif defined(PLATFORM_MICAZ) + components At45dbStorageManagerC; + DelugeStorageP.At45dbVolume[VOLUME_DELUGE0] -> At45dbStorageManagerC.At45dbVolume[VOLUME_DELUGE0]; + DelugeStorageP.At45dbVolume[VOLUME_DELUGE1] -> At45dbStorageManagerC.At45dbVolume[VOLUME_DELUGE1]; +#else + #error "Target platform is not currently supported by Deluge T2" +#endif - DelugeStorageP.SubBlockRead[0] -> BlockStorageC_0; - DelugeStorageP.SubBlockWrite[0] -> BlockStorageC_0; - DelugeStorageP.SubBlockRead[1] -> BlockStorageC_1; - DelugeStorageP.SubBlockWrite[1] -> BlockStorageC_1; + DelugeStorage[VOLUME_DELUGE0] = DelugeStorageP.DelugeStorage[VOLUME_DELUGE0]; + DelugeStorage[VOLUME_DELUGE1] = DelugeStorageP.DelugeStorage[VOLUME_DELUGE1]; components LedsC, MainC; DelugeStorageP.Leds -> LedsC; diff --git a/tos/lib/net/Deluge/DelugeStorageP.nc b/tos/lib/net/Deluge/DelugeStorageP.nc index 2bdb5f0b..67c9f6cc 100644 --- a/tos/lib/net/Deluge/DelugeStorageP.nc +++ b/tos/lib/net/Deluge/DelugeStorageP.nc @@ -33,10 +33,16 @@ module DelugeStorageP interface BlockWrite as SubBlockWrite[uint8_t img_num]; interface Boot; interface Leds; +#if defined(PLATFORM_TELOSB) + interface StorageMap[uint8_t img_num]; +#elif defined(PLATFORM_MICAZ) + interface At45dbVolume[volume_id_t img_num]; +#endif } provides { interface BlockRead[uint8_t img_num]; interface BlockWrite[uint8_t img_num]; + interface DelugeStorage[uint8_t img_num]; interface DelugeMetadata; interface Notify; @@ -170,6 +176,23 @@ implementation signal BlockWrite.syncDone[img_num](error); } + command storage_addr_t DelugeStorage.getPhysicalAddress[uint8_t img_num](storage_addr_t addr) + { + storage_addr_t p_addr = 0xFFFFFFFF; + + #if defined(PLATFORM_TELOSB) + p_addr = call StorageMap.getPhysicalAddress[img_num](addr); + #elif defined(PLATFORM_MICAZ) + at45page_t page = call At45dbVolume.remap[img_num]((addr >> AT45_PAGE_SIZE_LOG2)); + at45pageoffset_t offset = addr & ((1 << AT45_PAGE_SIZE_LOG2) - 1); + p_addr = page; + p_addr = p_addr << AT45_PAGE_SIZE_LOG2; + p_addr += offset; + #endif + + return p_addr; + } + default event void BlockRead.readDone[uint8_t img_num](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {} default event void BlockRead.computeCrcDone[uint8_t img_num](storage_addr_t addr, storage_len_t len, uint16_t crc, error_t error) {} default event void BlockWrite.writeDone[uint8_t img_num](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {} @@ -185,4 +208,10 @@ implementation command error_t Notify.enable() { return SUCCESS; } command error_t Notify.disable() { return SUCCESS; } + +#if defined(PLATFORM_TELOSB) + default command storage_addr_t StorageMap.getPhysicalAddress[uint8_t img_num](storage_addr_t addr) { return 0xFFFFFFFF; } +#elif defined(PLATFORM_MICAZ) + default command at45page_t At45dbVolume.remap[volume_id_t volid](at45page_t volumePage) { return 0xFFFF; }; +#endif } diff --git a/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerC.nc b/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerC.nc index b8a25f12..f05d8310 100644 --- a/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerC.nc +++ b/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerC.nc @@ -34,7 +34,7 @@ generic configuration FlashVolumeManagerC(am_id_t AMId) uses { interface BlockRead[uint8_t img_num]; interface BlockWrite[uint8_t img_num]; - interface StorageMap[uint8_t img_num]; + interface DelugeStorage[uint8_t img_num]; } } @@ -47,13 +47,13 @@ implementation FlashVolumeManagerP.BlockRead[0] = BlockRead[0]; FlashVolumeManagerP.BlockWrite[0] = BlockWrite[0]; - FlashVolumeManagerP.StorageMap[0] = StorageMap[0]; + FlashVolumeManagerP.DelugeStorage[0] = DelugeStorage[0]; FlashVolumeManagerP.BlockRead[1] = BlockRead[1]; FlashVolumeManagerP.BlockWrite[1] = BlockWrite[1]; - FlashVolumeManagerP.StorageMap[1] = StorageMap[1]; + FlashVolumeManagerP.DelugeStorage[1] = DelugeStorage[1]; FlashVolumeManagerP.SerialAMSender -> SerialAMSenderC; FlashVolumeManagerP.SerialAMReceiver -> SerialAMReceiverC; - FlashVolumeManagerP.Leds -> NoLedsC; + FlashVolumeManagerP.Leds -> LedsC; #ifdef DELUGE components NetProgC, new TimerMilliC(); diff --git a/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerP.nc b/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerP.nc index f31c7160..e5705277 100644 --- a/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerP.nc +++ b/tos/lib/net/Deluge/FlashVolumeManager/FlashVolumeManagerP.nc @@ -34,7 +34,7 @@ generic module FlashVolumeManagerP() uses { interface BlockRead[uint8_t img_num]; interface BlockWrite[uint8_t img_num]; - interface StorageMap[uint8_t img_num]; + interface DelugeStorage[uint8_t img_num]; interface AMSend as SerialAMSender; interface Receive as SerialAMReceiver; interface Leds; @@ -119,6 +119,13 @@ implementation } event void BlockWrite.eraseDone[uint8_t img_num](error_t error) + { + if (state == S_ERASE) { + call BlockWrite.sync[img_num](); + } + } + + event void BlockWrite.syncDone[uint8_t img_num](error_t error) { if (state == S_ERASE) { state = S_IDLE; @@ -126,8 +133,6 @@ implementation } } - event void BlockWrite.syncDone[uint8_t img_num](error_t error) {} - event void SerialAMSender.sendDone(message_t* msg, error_t error) {} event message_t* SerialAMReceiver.receive(message_t* msg, void* payload, uint8_t len) @@ -136,44 +141,55 @@ implementation SerialReqPacket *srpkt = (SerialReqPacket *)payload; SerialReplyPacket *serialMsg_payload = (SerialReplyPacket *)call SerialAMSender.getPayload(&serialMsg); + uint8_t img_num = 0xFF; + + // Converts the image number that the user wants to the real image number + switch (srpkt->img_num) { + case 0: + img_num = VOLUME_DELUGE0; + break; + case 1: + img_num = VOLUME_DELUGE1; + break; + } switch (srpkt->msg_type) { case SERIALMSG_ERASE: // === Erases a volume === state = S_ERASE; - error = call BlockWrite.erase[srpkt->img_num](); + error = call BlockWrite.erase[img_num](); break; case SERIALMSG_WRITE: // === Writes to a volume === state = S_WRITE; memcpy(buffer, srpkt->data, srpkt->len); - error = call BlockWrite.write[srpkt->img_num](srpkt->offset, + error = call BlockWrite.write[img_num](srpkt->offset, buffer, srpkt->len); break; case SERIALMSG_READ: // === Reads a portion of a volume === state = S_READ; - error = call BlockRead.read[srpkt->img_num](srpkt->offset, + error = call BlockRead.read[img_num](srpkt->offset, serialMsg_payload->data, srpkt->len); break; case SERIALMSG_CRC: // === Computes CRC over a portion of a volume === state = S_CRC; - error = call BlockRead.computeCrc[srpkt->img_num](srpkt->offset, + error = call BlockRead.computeCrc[img_num](srpkt->offset, srpkt->len, 0); break; case SERIALMSG_ADDR: // === Gets the physical starting address of a volume === *(nx_uint32_t*)(&serialMsg_payload->data) = - (uint32_t)call StorageMap.getPhysicalAddress[srpkt->img_num](0); + (uint32_t)call DelugeStorage.getPhysicalAddress[img_num](0); sendReply(SUCCESS, sizeof(SerialReplyPacket) + 4); break; #ifdef DELUGE case SERIALMSG_REPROG: // === Reboots and reprograms === state = S_REPROG; sendReply(SUCCESS, sizeof(SerialReplyPacket)); - img_num_reboot = srpkt->img_num; + img_num_reboot = img_num; call Timer.startOneShot(1024); break; case SERIALMSG_DISS: // === Starts disseminating a volume === - signal Notify.notify(srpkt->img_num); // Notifies Deluge to start disseminate + signal Notify.notify(img_num); // Notifies Deluge to start disseminate sendReply(SUCCESS, sizeof(SerialReplyPacket)); break; #endif @@ -205,5 +221,5 @@ implementation default command error_t BlockRead.read[uint8_t img_num](storage_addr_t addr, void* buf, storage_len_t len) { return FAIL; } default command error_t BlockRead.computeCrc[uint8_t img_num](storage_addr_t addr, storage_len_t len, uint16_t crc) { return FAIL; } - default command storage_addr_t StorageMap.getPhysicalAddress[uint8_t img_num](storage_addr_t addr) { return 0; } + default command storage_addr_t DelugeStorage.getPhysicalAddress[uint8_t img_num](storage_addr_t addr) { return 0; } } diff --git a/tos/lib/net/Deluge/extra/NetProgC.nc b/tos/lib/net/Deluge/extra/NetProgC.nc index f8896618..255d2c9b 100644 --- a/tos/lib/net/Deluge/extra/NetProgC.nc +++ b/tos/lib/net/Deluge/extra/NetProgC.nc @@ -46,9 +46,12 @@ implementation { NetProg = NetProgM; MainC.SoftwareInit -> NetProgM.Init; - NetProgM.StorageMap[0] -> DelugeStorageC.StorageMap[0]; - NetProgM.StorageMap[1] -> DelugeStorageC.StorageMap[1]; + NetProgM.DelugeStorage[VOLUME_DELUGE0] -> DelugeStorageC.DelugeStorage[VOLUME_DELUGE0]; + NetProgM.DelugeStorage[VOLUME_DELUGE1] -> DelugeStorageC.DelugeStorage[VOLUME_DELUGE1]; NetProgM.DelugeMetadata -> DelugeStorageC; NetProgM.IFlash -> IFlash; NetProgM.Crc -> CrcP; + + components LedsC; + NetProgM.Leds -> LedsC; } diff --git a/tos/lib/net/Deluge/extra/NetProgM.nc b/tos/lib/net/Deluge/extra/NetProgM.nc index 998a5fdb..93bed42c 100644 --- a/tos/lib/net/Deluge/extra/NetProgM.nc +++ b/tos/lib/net/Deluge/extra/NetProgM.nc @@ -37,10 +37,11 @@ module NetProgM { interface Init; } uses { - interface StorageMap[uint8_t img_num]; + interface DelugeStorage[uint8_t img_num]; interface InternalFlash as IFlash; interface Crc; interface DelugeMetadata; + interface Leds; } } @@ -103,7 +104,7 @@ implementation { atomic { writeTOSinfo(); - args.imageAddr = call StorageMap.getPhysicalAddress[img_num](0); + args.imageAddr = call DelugeStorage.getPhysicalAddress[img_num](0); args.gestureCount = 0xff; args.noReprogram = FALSE; call IFlash.write((uint8_t*)TOSBOOT_ARGS_ADDR, &args, sizeof(args)); @@ -122,6 +123,6 @@ implementation { return FAIL; } - default command storage_addr_t StorageMap.getPhysicalAddress[uint8_t img_num](storage_addr_t addr) { return 0xFFFFFFFF; } + default command storage_addr_t DelugeStorage.getPhysicalAddress[uint8_t img_num](storage_addr_t addr) { return 0xFFFFFFFF; } } diff --git a/tos/lib/net/Deluge/extra/avr/InternalFlashC.nc b/tos/lib/net/Deluge/extra/avr/InternalFlashC.nc new file mode 100644 index 00000000..ac24b502 --- /dev/null +++ b/tos/lib/net/Deluge/extra/avr/InternalFlashC.nc @@ -0,0 +1,65 @@ +// $Id$ + +/* tab:2 + * + * + * "Copyright (c) 2000-2005 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." + * + */ + +/** + * @author Jonathan Hui + */ + +#include "InternalFlash.h" + +module InternalFlashC { + provides interface InternalFlash; +} + +implementation { + + command error_t InternalFlash.write(void* addr, void* buf, uint16_t size) { + + uint8_t *addrPtr = (uint8_t*)addr; + uint8_t *bufPtr = (uint8_t*)buf; + + for ( ; size; size-- ) + eeprom_write_byte(addrPtr++, *bufPtr++); + + while(!eeprom_is_ready()); + + return SUCCESS; + + } + + command error_t InternalFlash.read(void* addr, void* buf, uint16_t size) { + + uint8_t *addrPtr = (uint8_t*)addr; + uint8_t *bufPtr = (uint8_t*)buf; + + for ( ; size; size-- ) + *bufPtr++ = eeprom_read_byte(addrPtr++); + + return SUCCESS; + + } + +} diff --git a/tos/lib/net/Deluge/extra/mica2/NetProg_platform.h b/tos/lib/net/Deluge/extra/mica2/NetProg_platform.h new file mode 100644 index 00000000..165cdef7 --- /dev/null +++ b/tos/lib/net/Deluge/extra/mica2/NetProg_platform.h @@ -0,0 +1,44 @@ +// $Id$ + +/* tab:2 + * + * + * "Copyright (c) 2000-2005 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." + * + */ + +/** + * @author Jonathan Hui + */ + +#ifndef __NETPROG_PLATFORM_H__ +#define __NETPROG_PLATFORM_H__ + +enum { + IFLASH_TOS_INFO_ADDR = 0xfe0, // 6 bytes + IFLASH_NODE_DESC_ADDR = 0xfe6, // 10 bytes +}; + +void netprog_reboot() { + wdt_enable(1); + while(1); +} + +#endif diff --git a/tos/lib/net/Deluge/extra/micaz/InternalFlash.h b/tos/lib/net/Deluge/extra/micaz/InternalFlash.h new file mode 100644 index 00000000..95ec7cd2 --- /dev/null +++ b/tos/lib/net/Deluge/extra/micaz/InternalFlash.h @@ -0,0 +1,41 @@ +// $Id$ + +/* tab:4 + * + * + * "Copyright (c) 2000-2004 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." + * + */ + +/** + * InternalFlash.h - Internal flash implementation for the avr + * platform. + * + * Valid address range is 0x0 - 0xFFF. + * + * @author Jonathan Hui + */ + +#ifndef __INTERNAL_FLASH_H__ +#define __INTERNAL_FLASH_H__ + +#include + +#endif diff --git a/tos/lib/net/Deluge/extra/micaz/TOSBoot_platform.h b/tos/lib/net/Deluge/extra/micaz/TOSBoot_platform.h new file mode 100644 index 00000000..736bb2e8 --- /dev/null +++ b/tos/lib/net/Deluge/extra/micaz/TOSBoot_platform.h @@ -0,0 +1,47 @@ +// $Id$ + +/* tab:2 + * "Copyright (c) 2000-2005 The Regents of the University of California. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose, without fee, and without written agreement is + * hereby granted, provided that the above copyright notice, the following + * two paragraphs and the author appear in all copies of this software. + * + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." + */ + +/** + * @author Jonathan Hui + */ + +#ifndef __TOSBOOT_PLATFORM_H__ +#define __TOSBOOT_PLATFORM_H__ + +enum { + // address of TOSBoot args in internal flash + TOSBOOT_ARGS_ADDR = 0xff0, + // number of resets to force golden image + TOSBOOT_GESTURE_MAX_COUNT = 3, + // address of the golden image in external flash + TOSBOOT_GOLDEN_IMG_ADDR = 0x0L, + // size of each internal program flash page + TOSBOOT_INT_PAGE_SIZE = SPM_PAGESIZE, +}; + +enum { + DELUGE_MIN_ADV_PERIOD_LOG2 = 9, + DELUGE_QSIZE = 2, +}; + +#endif -- 2.39.2