⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mote-mote radio communication - tinyos documentation wiki.htm

📁 从官方网站上下载tinyos2.0的学习指南
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<P>First, we need to identify the interfaces (and components) that provide 
access to the radio and allow us to manipulate the <CODE>message_t</CODE> type. 
Second, we must update the <CODE>module</CODE> block in the 
<CODE>BlinkToRadioC.nc</CODE> by adding <CODE>uses</CODE> statements for the 
interfaces we need. Third, we need to declare new variables and add any 
initialization and start/stop code that is needed by the interfaces and 
components. Fourth, we must add any calls to the component interfaces we need 
for our application. Fifth, we need to implmement any events specified in the 
interfaces we plan on using. Sixth, the <CODE>implementation</CODE> block of the 
application configuration file, <CODE>BlinkToRadioApp.c</CODE>, must be updated 
by adding a <CODE>components</CODE> statement for each component we use that 
provides one of the interfaces we chose earlier. Finally, we need to wire the 
the interfaces used by the application to the components which provide those 
interfaces. </P>
<P>Let's walk through the steps, one-by-one: </P>
<OL>
  <LI><B>Identify the interfaces (and components) that provide access to the 
  radio and allow us to manipulate the <CODE>message_t</CODE> type.</B> <BR>We 
  will use the <CODE>AMSend</CODE> interface to send packets as well as the 
  <CODE>Packet</CODE> and <CODE>AMPacket</CODE> interfaces to access the 
  <CODE>message_t</CODE> abstract data type. Although it is possible to wire 
  directly to the <CODE>ActiveMessageC</CODE> component, we will instead use the 
  <CODE>AMSenderC</CODE> component. However, we still need to start the radio 
  using the <CODE>ActiveMessageC.SplitControl</CODE> interface.The reason for 
  using <CODE>AMSenderC</CODE> is because it provides a virtualized abstraction. 
  Earlier versions of TinyOS did not virtualize access to the radio, so it was 
  possible for two components that were sharing the radio to interfere with each 
  other. It was not at all uncommon for one component to discover the radio was 
  busy because some other component, unknown to the first component, was 
  accessing the active message layer. Radio virtualization was introduced in 
  TinyOS 2.0 to address this interference and <CODE>AMSenderC</CODE> was written 
  to provide this virtualization. Every user of <CODE>AMSenderC</CODE> is 
  provided with a 1-deep queue and the queues of all users are serviced in a 
  fair manner. 
  <LI><B>Update the <CODE>module</CODE> block in the 
  <CODE>BlinkToRadioC.nc</CODE> by adding <CODE>uses</CODE> statements for the 
  interfaces we need:</B> <PRE>module BlinkToRadioC {
  ...
  uses interface Packet;
  uses interface AMPacket;
  uses interface AMSend;
  uses interface SplitControl as AMControl;
}
</PRE>
  <P>Note that <CODE>SplitControl</CODE> has been renamed to 
  <CODE>AMControl</CODE> using the <CODE>as</CODE> keyword. nesC allows 
  interfaces to be renamed in this way for several reasons. First, it often 
  happens that two or more components that are needed in the same module provide 
  the same interface. The <CODE>as</CODE> keyword allows one or more such names 
  to be changed to distinct names so that they can each be addressed 
  individually. Second, interfaces are sometimes renamed to something more 
  meaningful. In our case, <CODE>SplitControl</CODE> is a general interface used 
  for starting and stopping components, but the name <CODE>AMControl</CODE> is a 
  mnemonic to remind us that the particular instance of 
  <CODE>SplitControl</CODE> is used to control the <CODE>ActiveMessageC</CODE> 
  component. </P>
  <LI><B>Declare any new variables and add any needed initialization code.</B> 
  <BR>First, we need to declare some new module-scope variables. We need a 
  <CODE>message_t</CODE> to hold our data for transmission. We also need a flag 
  to keep track of when the radio is busy sending. These declarations need to be 
  added in the <CODE>implementation</CODE> block of 
  <CODE>BlinkToRadioC.nc</CODE>: <PRE>implementation {
  bool busy = FALSE;
  message_t pkt;
  ...
}
</PRE>
  <P>Next, we need to handle the initialization of the radio. The radio needs to 
  be started when the system is booted so we must call 
  <CODE>AMControl.start</CODE> inside <CODE>Boot.booted</CODE>. The only 
  complication is that in our current implementation, we start a timer inside 
  <CODE>Boot.booted</CODE> and we are planning to use this timer to send 
  messages over the radio but the radio can't be used until it has completed 
  starting up. The radio signals that it has completed starting through the 
  <CODE>AMControl.startDone</CODE> event. To ensure that we do not start using 
  the radio before it is ready, we need to postpone starting the timer until 
  after the radio has completed starting. We can accomplish this by moving the 
  call to start the timer, which is now inside <CODE>Boot.booted</CODE>, to 
  <CODE>AMControl.startDone</CODE>, giving us a new <CODE>Boot.booted</CODE> 
  with the following body: </P><PRE>  event void Boot.booted() {
    call AMControl.start();
  }
</PRE>
  <P>We also need to implement the <CODE>AMControl.startDone</CODE> and 
  <CODE>AMControl.stopDone</CODE> event handlers, which have the following 
  bodies: </P><PRE>  event void AMControl.startDone(error_t err) {
    if (err == SUCCESS) {
      call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
    }
    else {
      call AMControl.start();
    }
  }

  event void AMControl.stopDone(error_t err) {
  }
</PRE>
  <P>If the radio is started successfully, <CODE>AMControl.startDone</CODE> will 
  be called with the <CODE>error_t</CODE> parameter set to a value of 
  <CODE>SUCCESS</CODE>. If the radio starts successfully, then it is appropriate 
  to start the timer. If, however, the radio does not start successfully, then 
  it obviously cannot be used so we try again to start it. This process 
  continues until the radio starts, and ensures that the node software doesn't 
  run until the key components have started successfully. If the radio doesn't 
  start at all, a human operator might notice that the LEDs are not blinking as 
  they are supposed to, and might try to debug the problem. </P>
  <LI><B>Add any program logic and calls to the used interfaces we need for our 
  application.</B> <BR>Since we want to transmit the node's id and counter value 
  every time the timer fires, we need to add some code to the 
  <CODE>Timer0.fired</CODE> event handler: <PRE>event void Timer0.fired() {
  ...
  if (!busy) {
    BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)(call Packet.getPayload(&amp;pkt, NULL));
    btrpkt-&gt;nodeid = TOS_NODE_ID;
    btrpkt-&gt;counter = counter;
    if (call AMSend.send(AM_BROADCAST_ADDR, &amp;pkt, sizeof(BlinkToRadioMsg)) == SUCCESS) {
      busy = TRUE;
    }
  }
}
</PRE>
  <P>This code performs several operations. First, it ensures that a message 
  transmission is not in progress by checking the busy flag. Then it gets the 
  packet's payload portion and casts it to a pointer to the previously declared 
  <CODE>BlinkToRadioMsg</CODE> external type. It can now use this pointer to 
  initialise the packet's fields, and then send the packet by calling 
  <CODE>AMSend.send</CODE>. The packet is sent to all nodes in radio range by 
  specyfing <CODE>AM_BROADCAST_ADDR</CODE> as the destination address. Finally, 
  the test against SUCCESS verifies that the AM layer accepted the message for 
  transmission. If so, the busy flag is set to true. For the duration of the 
  send attempt, the packet is owned by the radio, and user code must not access 
  it. Note that we could have avoided using the <CODE>Packet</CODE> interface, 
  as it's <CODE>getPayload</CODE> command is repeated within 
  <CODE>AMSend</CODE>. </P>
  <LI><B>Implmement any (non-initialization) events specified in the interfaces 
  we plan on using.</B> <BR>Looking through the <CODE>Packet</CODE>, 
  <CODE>AMPacket</CODE>, and <CODE>AMSend</CODE> interfaces, we see that there 
  is only one <CODE>event</CODE> we need to worry about, 
  <CODE>AMSend.sendDone</CODE>: <PRE>  /**
   * Signaled in response to an accepted send request. msg is
   * the message buffer sent, and error indicates whether
   * the send was successful.
   *
   * @param  msg   the packet which was submitted as a send request
   * @param  error SUCCESS if it was sent successfully, FAIL if it was not,
   *               ECANCEL if it was cancelled
   * @see send
   * @see cancel
   */
  event void sendDone(message_t* msg, error_t error);
</PRE>
  <P>This event is signaled after a message transmission attempt. In addition to 
  signaling whether the message was transmitted successfully or not, the event 
  also returns ownership of <CODE>msg</CODE> from <CODE>AMSend</CODE> back to 
  the component that originally called the <CODE>AMSend.send</CODE> command. 
  Therefore <CODE>sendDone</CODE> handler needs to clear the <CODE>busy</CODE> 
  flag to indicate that the message buffer can be reused: </P><PRE>  event void AMSend.sendDone(message_t* msg, error_t error) {
    if (&amp;pkt == msg) {
      busy = FALSE;
    }
  }
</PRE>
  <P>Note the check to ensure the message buffer that was signaled is the same 
  as the local message buffer. This test is needed because if two components 
  wire to the same <CODE>AMSend</CODE>, <I>both</I> will receive a 
  <CODE>sendDone</CODE> event after <I>either</I> component issues a 
  <CODE>send</CODE> command. Since a component writer has no way to enforce that 
  her component will not be used in this manner, a defensive style of 
  programming that verifies that the sent message is the same one that is being 
  signaled is required. </P>
  <LI><B>Update the <CODE>implementation</CODE> block of the application 
  configuration file by adding a <CODE>components</CODE> statement for each 
  component used that provides one of the interfaces chosen earlier.</B> <BR>The 
  following lines can be added just below the existing <CODE>components</CODE> 
  declarations in the <CODE>implementation</CODE> block of 
  <CODE>BlinkToRadioAppC.nc</CODE>: <PRE>implementation {
  ...
  components ActiveMessageC;
  components new AMSenderC(AM_BLINKTORADIO);
  ...
}
</PRE>
  <P>These statements indicate that two components, <CODE>ActiveMessageC</CODE> 
  and <CODE>AMSenderC</CODE>, will provide the needed interfaces. However, note 
  the slight difference in their syntax. <CODE>ActiveMessageC</CODE> is a 
  singleton component that is defined once for each type of hardware platform. 
  <CODE>AMSenderC</CODE> is a generic, parameterized component. The 
  <CODE>new</CODE> keyword indicates that a new instance of 
  <CODE>AMSenderC</CODE> will be created. The <CODE>AM_BLINKTORADIO</CODE> 
  parameter indicates the AM type of the <CODE>AMSenderC</CODE>. We can extend 
  the <CODE>enum</CODE> in the <CODE>BlinkToRadio.h</CODE> header file to 
  incorporate the value of <CODE>AM_BLINKTORADIO</CODE>: </P><PRE>...
enum {
  AM_BLINKTORADIO = 6,
  TIMER_PERIOD_MILLI = 250
};
...
</PRE>
  <LI><B>Wire the the interfaces used by the application to the components which 
  provide those interfaces.</B> <BR>The following lines will wire the used 
  interfaces to the providing components. These lines should be added to the 
  bottom of the <CODE>implementation</CODE> block of 
  <CODE>BlinkToRadioAppC.nc</CODE>: <PRE>implementation {
  ...
  App.Packet -&gt; AMSenderC;
  App.AMPacket -&gt; AMSenderC;
  App.AMSend -&gt; AMSenderC;
  App.AMControl -&gt; ActiveMessageC;
}
</PRE></LI></OL><A name=Receiving_a_Message_over_the_Radio></A>
<H1><SPAN class=mw-headline>Receiving a Message over the Radio</SPAN></H1>
<P>Now that we have an application that is transmitting messages, we can add 
some code to receive and process the messages. Let's write code that, upon 
receiving a message, sets the LEDs to the three least significant bits of the 
counter in the message. To make this application interesting, we will want to 
remove the line <CODE><STRIKE>call Leds.set(counter);</STRIKE></CODE> from the 
<CODE>Timer0.fired</CODE> event handler. Otherwise, both the timer events and 
packet receptions will update the LEDs and the resulting effect will be bizarre. 
</P>
<P>If two motes are programmed with our modified application, then each will 
display the other mote's counter value. If the motes go out of radio range, then 
the LEDs will stop changing. You can even investigate link asymmetry by trying 
to get one mote's LEDs to keep blinking while the other mote's LEDs stop 
blinking. This would indicate that the link from the non-blinking mote to 
blinking mote was available but that the reverse channel was no longer 
available. </P>
<OL>
  <LI><B>Identify the interfaces (and components) that provide access to the 
  radio and allow us to manipulate the <CODE>message_t</CODE> type.</B> <BR>We 
  will use the <CODE>Receive</CODE> interface to receive packets. 
  <LI><B>Update the module block in the BlinkToRadioC.nc by adding uses 
  statements for the interfaces we need:</B> <PRE>module BlinkToRadioC {
  ...
  uses interface Receive;
}
</PRE>
  <LI><B>Declare any new variables and add any needed initialization code.</B> 
  <BR>We will not require any new variables to receive and process messages from 
  the radio. 
  <LI><B>Add any program logic and calls to the used interfaces we need for our 
  application.</B> <BR>Message reception is an event-driven process so we do not 
  need to call any commands on the <CODE>Receive</CODE>. 
  <LI><B>Implemement any (non-initialization) events specified in the interfaces 
  we plan on using.</B> <BR>We need to implement the 
  <CODE>Receive.receive</CODE> event handler: <PRE>event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) {
  if (len == sizeof(BlinkToRadioMsg)) {
    BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)payload;
    call Leds.set(btrpkt-&gt;counter);
  }
  return msg;
}
</PRE>
  <P>The <CODE>receive</CODE> event handler performs some simple operations. 
  First, we need to ensure that the length of the message is what is expected. 
  Then, the message payload is cast to a structure pointer of type 
  <CODE>BlinkToRadioMsg*</CODE> and assigned to a local variable. Then, the 
  counter value in the message is used to set the states of the three LEDs.Note 
  that we can safely manipulate the <CODE>counter</CODE> variable outside of an 
  atomic section. The reason is that receive event executes in task context 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -