Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LWMAC: A simple duty cycling 802.15.4 MAC protocol (2nd try). #6554

Merged
merged 3 commits into from
Jun 26, 2017

Conversation

zhuoshuguo
Copy link
Contributor

@zhuoshuguo zhuoshuguo commented Feb 5, 2017

This is a second trial of LWMAC, which is an enhanced version of X-MAC (with phase-lock scheme), and is originally designed and implemented by @daniel-k .

In short, I have adapted and rebased the original LWMAC onto the gnrc_mac module.
However, this LWMAC here in this PR still contains its (origin) own timeout module (it suppose to use gnrc_mac's timeout module which is based on evtimer ). As soon as the evtimer will be merged, I will remove LWMAC's timeout module and use gnrc_mac's timeout module instead.

Notably, the current implementation of LWMAC uses RTT as the underlying timer source. So, currently, the protocol cannot run on nodes that don't have RTT. But, as a long-term plan, we will replace RTT by a general timer API (like evtimer) as the underlying timer to make LWMAC suitable for a larger scale of devices, when the related implementations are ready.

More tests and review are welcome. I will continue to update it according to your feedbacks. Let's get LWMAC merged this time. :-)

The basic scheme of LWMAC:

riot-adt-engineers-sg

  • LWMAC adopts the radio duty-cycle scheme. Namely, in each cycle period (frame), a node device wakes up for a short period of time (called listen period or wake period) for receiving possible incoming packets from other devices. Outside the listen period, the node device turns off its radio to conserve power.

  • LWMAC adopts the phase-lock scheme to further reduce power consumption. Each node device in LWMAC will try to record/track its Tx-neighbor's wake phase. This is also called phase-lock. After phase-locking, the sender node will (likely) spend less preamble packets (also called WR packets in LWMAC) for initiating a hand-shaking procedure for transmitting a data packet, compared to the first time it talks to the receiver. The phase-lock scheme is also shown in the above figure.

Besides, @daniel-k (just to let you know), I have also made some revisions to LWMAC:

  • LWMAC adopts pending-bit technique to enhance its throughput. Namely, in case of having multi packets for the receiver, a sender uses the pending-bit embedded in the MAC header for instruction of this situation, and buffered packets will be transmitted in a continuous sequence, back to back, to the receiver in one shot. To this end, a sender can send more packets to the receiver in one cycle duration.

  • LWMAC adopts wakeup auto extension scheme based on timeout (like T-MAC). In short, when a packet is successfully received at the receiver side, the receiver will reset the wakeup timeout to extend its wakeup period for receiving more potential incoming packets. This is to be compatible with the pending-bit technique to allow the receiver to absorb more packets when needed, thus boosts the throughput.

  • LWMAC adopts simple retransmission scheme to enhace link reliability. The origin LWMAC will drop the data packet if it didn't receive a reply (WA/preamble-ACK) from the receiver after one single full LWMAC_PREAMBLE_DURATION_US period. While in multi-senders scenarios or multi-hop scenarios in which several senders may try to transmit WRs at the same time and it is quite easy for senders to loose WA from the receiver due to interferences, leading to (frequent) packet drops. To this end, I simply added a retransmission counter, that data packet will only be dropped in case the retransmission counter gets larger than LWMAC_DATA_TX_RETRIES

  • LWMAC adopts a automatic phase backoff scheme to reduce WR (Preamble) collision probability. In multi-hop scenarios, let's say nodes A <---B <----C (which is common in multi-hop data collection networks), in which B has packets for A, and C has packets for B. In case A and B's wakeup phases are too close (overlapping). Then, especially in high traffic conditions, B and C may initiate transmissions at the same time (B sends to A, while C sends to B), a link of either will be definitely interfered, leading to collisions and link throughput reductions. To this end, by using the automatic phase backoff scheme, if a sender finds its receiver's phase is too close to its own phase, it will run backoff scheme to randomly reselect a new wakeup phase for itself.

A typical transmission procedure you will oberve on sniffer:

1) first handshake and data transmission:

sniffer-1
When a sender first sends data to a phase-unkown receiver, normally it spends longer preamble procedure for finding the receiver's wake-up phase. As shown in the above figure, the former four packets are all repeated preamble packets. The fifth packet is the preamble-ACK packet replied from the receiver. And then, comes the data packet and ACK.

After the first handshake, the sender will record the receiver's phase. So, the next time when the sender wants to send data packet to the same receiver, it wakes up just a little bit in advance to the receiver's listen period and then starts the preamble. It is expected that, after phase-locking, the preamble of the sender will be much quicker replied by the preamble-ACK of the receiver. As shown in the below figure.

2) second handshake and data transmission (the same for the following ones, before phase-lock failure due to timer drift):

sniffer-2

This time, after phase-locking, the first preamble is quickly replied by the preamble-ACK of the receiver. In this manner, power consumption on the sender side will be redueced.

In case of phase-lock failure due to timer drift (let's say the first preamble didn't get immediately replied by the preamble-ACK), the sender simply continue its preamble procedure until it gets the preamble-ACK again, like the first time it talks to the receiver. And then, the phase of the receiver gets updated again on the sender.

Print out the achieved duty-cyle of LWMAC:

You can print out the achieved radio duty-cyle (currently a roughly one) of LWMAC by setting the LWMAC_ENABLE_DUTYCYLE_RECORD flag in sys/include/net/gnrc/lwmac/types.h to "1".

By doing so, each time when a device sends or receives a packet, it will print out its achieved duty-cycle (start from power-up or reboot).

Also, by further enabling the debug flag in sys/net/gnrc/link_layer/lwmac/tx_state_machine.c you will get the printout of how many preamble (WR) and time (sending delay) cost for sending this packet in the TX procedure of LWMAC.

For instance:
sender side:

2017-02-18 17:35:44,664 - INFO # Welcome to RIOT!
> txtsnd 4 79:67:35:7e:54:3a:79:f6  helloworld
2017-02-18 17:35:49,545 - INFO #  txtsnd 4 79:67:35:7e:54:3a:79:f6  helloworld
> 2017-02-18 17:35:49,635 - INFO #  [lwmac-tx]: spent 8 WR in TX
2017-02-18 17:35:49,639 - INFO # [lwmac-tx]: pkt sending delay in TX: 75378 us
2017-02-18 17:35:49,643 - INFO # [lwmac-tx]: achieved duty-cycle: 13 % 

receiver side:

2017-02-18 17:35:46,096 - INFO # Welcome to RIOT!
> 2017-02-18 17:35:49,639 - INFO #  [lwmac-tx]: achieved duty-cycle: 13 % 
2017-02-18 17:35:49,641 - INFO # PKTDUMP: data received:
2017-02-18 17:35:49,646 - INFO # ~~ SNIP  0 - size:  10 byte, type: NETTYPE_UNDEF (0)
2017-02-18 17:35:49,649 - INFO # 000000 68 65 6c 6c 6f 77 6f 72 6c 64
2017-02-18 17:35:49,654 - INFO # ~~ SNIP  1 - size:  24 byte, type: NETTYPE_NETIF (-1)
2017-02-18 17:35:49,656 - INFO # if_pid: 4  rssi: 63  lqi: 252
2017-02-18 17:35:49,657 - INFO # flags: 0x0
2017-02-18 17:35:49,660 - INFO # src_l2addr: 79:67:08:77:01:9f:33:1e
2017-02-18 17:35:49,664 - INFO # dst_l2addr: 79:67:35:7e:54:3a:79:f6
2017-02-18 17:35:49,667 - INFO # ~~ PKT    -  2 snips, total size:  34 byte

lwmac_dutycycle

The above figure shows the radio duty-cycle of LWMAC (in idle listening state), as a function of the wake-up frequency (or, can be also called channel check rate), measured on the samr21 board.
It can be expected that the radio duty-cycle of LwMAC is proportional to the wake-up frequency, as it has a linear relation with the wake-up frequency.

How to test:

Currently, it seems that you can only use the samr21-xpro board to test this MAC, since some certain features of the protocol are only available on that platform (see LWMAC).
But, I don't know this (i.e., you can only use the samr21-xpro) still holds or not. Due to more drivers available now, maybe it also works on other boards as well. So, you are welcome to give it a try on other boards!!

Test by using the default example:
I have simply copied the default example from RIOT/examples to build a text example in RIOT/tests/lw_mac for testing this duty-cycle protocol.

$ cd tests/lw_mac
$ BOARD=samr21-xpro make flash term

Manually send packet from one board to the other via interactive shell:

txtsnd 4 79:67:1e:77:62:9b:71:f2  helloworld

you can also broadcast a packet by typing:

txtsnd 4 bcast helloworld

Try UDP transmissions with LWMAC:

For trying UDP transmissions by using LWMAC as your MAC layer, you can switch to RIOT/examples/gnrc_networking/ example (in this branch), and flash your boards:

$ cd examples/gnrc_networking
$ BOARD=samr21-xpro make flash term

Then, as instructed in gnrc_networking/README file, you can first start a UDP server on your node-A:

udp server start 8808

use ifconfig command to get node-A's IP address:

    > ifconfig
    Iface  7   HWaddr: ce:f5:e1:c5:f7:5a
               inet6 addr: ff02::1/128  scope: local [multicast]
               inet6 addr: fe80::ccf5:e1ff:fec5:f75a/64  scope: local
               inet6 addr: ff02::1:ffc5:f75a/128  scope: local [multicast]

On your node-B, try to send message to node-A using UDP:

udp send fe80::ccf5:e1ff:fec5:f75a 8808 testmessage

Some evaluation results:

Here are some evaluation results (on SAMR21 test-bed) to share, which are from a simple, star-topology, one receiver and multi-senders experimental scenario.

Handle contention

This simple test evaluates the impacet of sender number on LWMAC's performance, in terms of packet delay, packet reception ratio, sender duty-cycle and receiver duty-cycle.

Test settings:

  • Each sender adopts a data rate of 2 packets per second through the test, and each data packet contains a raw payload of 80 bytes.

  • the cycle duration ofLWMAC in this evalution experiment is enlarged to 500ms.

  • Each test scenario lasts for 300 seconds.

  • All the other parameters of LWMAC are the same as in this branch

Note that, by setting the data-rate the same as the channel-check-rate, i.e., both to 2Hz, this means that, averagely, all the sender will attend the competition for transmissions in each cycle of the receiver. This critical data rate setting (i.e., equals the channel-check-rate,) intends to evaluate LWMAC's reliability on handling transmission competitions/collisions and maintaining link quality.
lwmac

Stability evaluation 1

This test intends to evaluate the stability of LWMAC for running over a long time.

Setting: one receiver, three senders all sending to the same receiver.
Cycle duration of LWMAC: 100ms;
Data rate: 1 packet / 1 second per node;
Test duration: larger than 48 hours.

Results:

2017-04-30 16:41:10,890 - INFO # c13a, 176510, 176508, 528986. 
2017-04-30 16:41:11,094 - INFO # 2c02, 176304, 176304, 528987. 
2017-04-30 16:41:11,591 - INFO # 383a, 176176, 176176, 528988.

Packet reception ratio: 528988 /528990 = ( > 99.99%), only two packets lost out of 528988.

PS: during one shot of long time test, one node experienced a FAILED ASSERTION halted:

2017-04-28 05:52:51,521 - INFO # WARNING: [lwmac-tx] No response from destination
2017-04-28 05:52:51,657 - INFO # WARNING: [lwmac] TX 1 times retry
2017-04-28 05:52:51,659 - INFO # 0x66f3
2017-04-28 05:52:51,661 - INFO # *** RIOT kernel panic:
2017-04-28 05:52:51,662 - INFO # FAILED ASSERTION.
2017-04-28 05:52:51,663 - INFO # 
2017-04-28 05:52:51,670 - INFO # 	pid | name                 | state    Q | pri | stack ( used) | base       | current    
2017-04-28 05:52:51,678 - INFO # 	  - | isr_stack            | -        - |   - |   512 (  140) | 0x20000000 | 0x200001c0
2017-04-28 05:52:51,686 - INFO # 	  1 | idle                 | pending  Q |  15 |   256 (  132) | 0x200003e8 | 0x20000464 
2017-04-28 05:52:51,694 - INFO # 	  2 | main                 | bl mutex _ |   7 |  1536 (  460) | 0x200004e8 | 0x2000091c 
2017-04-28 05:52:51,703 - INFO # 	  3 | pktdump              | bl rx    _ |   6 |  1536 (  348) | 0x20003a98 | 0x20003f8c 
2017-04-28 05:52:51,711 - INFO # 	  4 | at86rf2xx-lwmac      | running  Q |   2 |  1024 (  652) | 0x200011ac | 0x20001424 
2017-04-28 05:52:51,719 - INFO # 	  5 | data_app             | bl mutex _ |   8 |  1536 (  660) | 0x20000ba0 | 0x20001014 
2017-04-28 05:52:51,724 - INFO # 	    | SUM                  |            |     |  6400 ( 2392)
2017-04-28 05:52:51,725 - INFO # 
2017-04-28 05:52:51,726 - INFO # *** halted.
2017-04-28 05:52:51,726 - INFO # 

arm-none-eabi-addr2line infers this FAILED ASSERTION halted to at86rf2xx_netdev.c:558, that may have something to do with issue 5486.

Stability evaluation 2

Settings:
Topology: see below, a multi-hop test-bed of SAMR21-xpro with at most 3 hops transmission. All the nodes were deployed in my office room environment (all nodes are in each other's radio/interference range).
2094878 1300000001
Application: based on the default application in RIOT/examples/default
Cycle duration of LWMAC for all nodes: 100ms;
data rate: 1 packet / 10 seconds per node.
Maximum link layer packet retransmission: 3 times.
Experiment duration: 50 hours (> two days)

results:

Info: node ID, generated data count, received data count, Total received data count at sink

2017-05-13 20:04:30,075 - INFO # 79f6, 18186, 18186, 90337. 
2017-05-13 20:04:30,160 - INFO # 383a, 17677, 17677, 90338. 
2017-05-13 20:04:31,954 - INFO # 2c02, 18131, 18131, 90339. 
2017-05-13 20:04:38,055 - INFO # 4c66, 18165, 18165, 90340. 
2017-05-13 20:04:39,951 - INFO # 8032, 18182, 18182, 90341.

None packet drop. Packet deliver ratio: 90341/90341 = 100%.

Stability evaluation 3

Run a third time experiment for evaluating LWMAC's stability:
settings:
image
This experiment is based on the examples/gnrc_networking which includes UDP and RPL.
There are one sink and 5 senders.
The sink initiates the RPL network and sets itself as the root. All the senders send packets to sink using UDP.
In the experiment, there are simultaneously two types of traffics:
1, upward traffic generated by son noders (senders) heading to the sink,
2, downward traffic generated by the sink heading to all senders.

For upward traffic, all senders use UDP to send packets to the link local address of the sink (bypass RPL, since I found that configured IPv6 address for RPL will expire (time out and disappear) on the son nodes (senders) after a certain period of time);
For downward traffic, the sink uses UDP to send packets to the configured ipv6 addresses of all the senders which are informed to the sink through RPL networking, i.e., downward traffic is based on RPL routing.

Other key MAC settings:
Cycle duration of LWMAC for all nodes: 100ms;
Maximum link layer packet retransmission: 3 times.

Data rate:

  1. for upward traffic of senders: 1 packet/2 seconds per sender;
  2. for downward traffic of sink: 1 packet/5 seconds (i.e., the sink sends a data to each specific sender every 25 seconds).

The experiment lasted about 48 hours (two days).

Results:
For upward traffic: 443461 (received) / 443481 (generated) = 99.9955%
For downward traffic : 35435 (received) / 35443 (generated) = 99.977%

Stability evaluation 4

Finished a 4th long-time experiment (the final one) for evaluating LWMAC's stability:
Settings:
image

Topology: one sink (receiver) and 5 senders:
This experiment is based on examples/default
5 senders adopt an intensive data rate for continuing generating data packets and sending to the sink;
Data rate for each sender: 5packets/1second;
MAC cycle duration for all nodes: 100ms;
MAC Tx-Queue size for each node: 10 packets;
Experiment duration: 61 hours;

Notably, the taffic of the network (taffic loads from all the senders) is beyong the offered throughput of LWMAC. And by applying such an overwhelming taffic, the goal of this experiment is to check that:

  1. Given the intensive data rate, and thus, intensive memory/buffer allocation and release manipulations, will LWMAC lead to memory leak or stack overflow, i.e., to see whether the protocol still has critical bugs of inproper memory/buffer manipulation;
  2. to test the robustness of the protocol that, given an overwhelming traffic rate, whether the protocol can still maintain basic communication functionality, i.e., normal sending/receiving. We don't want LWMAC dead (not functioning) in case of overwhelming taffic situation.

Results:

  1. After 61 hours running time, no devices go dead, or be halted.
  2. LWMAC succesfully maintains normal sending/receiving capability; To be more specific, all the nodes keep succesfully delivering their packets to the receiver, although most of the generated packet will be dropped due to Tx-queue full or meeting the maximum Tx-retry limit.

@zhuoshuguo zhuoshuguo changed the title Lw-mac: A aimple duty cycling 802.15.4 MAC protocol (a second trial). Lw-mac: A simple duty cycling 802.15.4 MAC protocol (a second trial). Feb 5, 2017
@emmanuelsearch
Copy link
Member

So if I understand correctly this example is with:

  • a wake-up period of 100ms on the listener side,
  • for a trial period of max 210ms, repeating every 7ms a preamble on the sender side, until sending is possible.
    Is that correct?
    How long is the listening phase on the listener side?

@emmanuelsearch emmanuelsearch added Area: network Area: Networking Type: new feature The issue requests / The PR implemements a new feature for RIOT labels Feb 6, 2017
@emmanuelsearch emmanuelsearch added this to the Release 2017.04 milestone Feb 6, 2017
@zhuoshuguo
Copy link
Contributor Author

a wake-up period of 100ms on the listener side,

Yes, I haven't changed the defualt setting of the original Lw-MAC in PR-3730. And, the wake interval is set currently to 100ms. Of cause, this parameter can be adjusted according to users.

for a trial period of max 210ms, repeating every 7ms a preamble on the sender side, until sending is possible.
Is that correct?

Generally correct. I would say, for a trial period of 210ms (this can be larger, for example, 1 second), repeating every 7ms a preamble on the sender side, until the receiver replies a preamble-ACK to tell the sender it is now in the reception period for receiving data.

How long is the listening phase on the listener side

The wake up period (listening phase) is set to twice the size of preamble invterval, to guarantee the reception of a preamble packet:

#ifndef LWMAC_WAKEUP_DURATION_US
#define LWMAC_WAKEUP_DURATION_US        (LWMAC_TIME_BETWEEN_WR_US * 2)
#endif

In this case, the listening phase will be 2*7ms = 14ms.

@zhuoshuguo
Copy link
Contributor Author

zhuoshuguo commented Feb 6, 2017

In short, given a listening phase of 2*7ms = 14ms, the larger the LWMAC_WAKEUP_INTERVAL_US is, the lower the average radio duty-cycle will be (in idle listening).

@emmanuelsearch
Copy link
Member

Tested on samr21 could send/receive packets

@emmanuelsearch
Copy link
Member

would be useful to display on the sender side the number of preambles sent + delay from the time where data is available to send, and the time where the packet is actually sent.

@emmanuelsearch
Copy link
Member

would also be useful to have an example with UDP

@zhuoshuguo
Copy link
Contributor Author

Will work on those suggestions soon.

@smlng
Copy link
Member

smlng commented Feb 17, 2017

@zhuoshuguo just for clarification: is this PR based on the old code in #3730? If so, where are the original commit by @daniel-k, would be nice then to keep his commits to honor is work.

@smlng
Copy link
Member

smlng commented Feb 17, 2017

further, we should close #3730.

@miri64
Copy link
Member

miri64 commented Feb 17, 2017

@zhuoshuguo just for clarification: is this PR based on the old code in #3730? If so, where are the original commit by @daniel-k, would be nice then to keep his commits to honor is work.

We (@daniel-k, @zhuoshuguo and I) changed a lot to RIOT's API to include it, so the make-up of it might now be a little different, so I could understand, why @zhuoshuguo decided to make all-new commits. @daniel-k's work is also honored by the @author tag and the copyright ;-).

@miri64
Copy link
Member

miri64 commented Feb 17, 2017

+ I'm getting more and more the feeling that commit authorship is more about blaming, not honoring other people ^^"

@zhuoshuguo
Copy link
Contributor Author

@smlng Good suggestion! Yes, this PR is based on the old codes in #3730. But, since the author of #3730 didn't have time to push it forward in #3730, so, as a simple solution for this situation, I took it over and built a new PR for continuing pushing it. Also, actually, I really don't know how to include the old commits in such a case, maybe there is a method for it in git but I am not aware of it. :-/

@smlng
Copy link
Member

smlng commented Feb 17, 2017

was just asking -- if @daniel-k is fine with it, I do not object. Anyhow, what about closing #3730 its an old, duplicate and we have enough open PRs to take off...

@zhuoshuguo
Copy link
Contributor Author

@miri64 Thanks for the clarification. :-)

@daniel-k
Copy link
Member

Hey guys! First of all thanks to @zhuoshuguo for taking over the "mess" I've left behind 🙂 I wish I would have (had) more time to push this forward myself, but unfortunately I don't. Concerning the attribution aspect, I'm okay with staying in @author tag as @miri64 suggests, Git commit authorship is not too important.

@zhuoshuguo
Copy link
Contributor Author

Added UDP transmission example, which is based on RIOT/examples/gnrc_networking/example.

@zhuoshuguo
Copy link
Contributor Author

zhuoshuguo commented Feb 25, 2017

Till now, have cleaned up the codes again and tackled all the remaining coding-style and comment-style issues I could find. Also, personally, I believe that the functionality of Lw-MAC is complete now.

So, ping~ Any comments for Lw-MAC for pushing it towards getting merged (I think it is close now) ? :-)

@zhuoshuguo
Copy link
Contributor Author

zhuoshuguo commented Feb 28, 2017

Through tests, found that, especially in multi-hop networks, Lw-MAC is still prone to link breakdown and packet drops, mainly due to WR (preamble) collisions among multi senders. Have thought of a way to fix it. Will update soon.

@daniel-k
Copy link
Member

How does your test case look like? To be honest, I didn't consider multi-hop too much if I remember correctly. Guess there's still potential for improvement :)

@zhuoshuguo
Copy link
Contributor Author

I have tested Lw-MAC on a linear 5-hops (6 nodes) test-bed, and tried 5-hops transmissions, (e.g., from the left-end node to the right-end node.) And, different WRs from different senders will interrupt with each other and result in link breakdown for almost all senders (when there are more senders). The backoff scheme of WR doesn't work well.

And, yes, there are indeed some room for improvement! :-) And I have already done some (will reflect on this PR soon).
Generally, I think the improvements of Lw-MAC will be on these two aspects:
(1) Solve WR (preamble) collisions. Actually, in my previous updates, I have already tried to improve this issue a little bit. But, now, from the results on multi-hop test-bed, the old improvement is not enough. So, I will use some other schemes.
(2) Improve the throughput of Lw-MAC. The original Lw-MAC only support one packet transmission and reception between a communication pair, in one wake-up period. In other words, for a sender, it can only send one packet to the receiver during receiver's wake-up period. If the sender has two packets for the receiver, it will have to use (receiver's) two cycles to transmit the two packets. To this end, I adopt the pending-bit scheme to allow kind of burst transmissions (by using the pending-bit embedded in the MAC header for instruction, buffered packets will be transmitted in a continuous sequence, back to back, to the receiver in one shot). This is similar to the continuous transmission scheme of T-MAC. :-)

@daniel-k
Copy link
Member

I have tested Lw-MAC on a linear 5-hops (6 nodes) test-bed, and tried 5-hops transmissions, (e.g., from the left-end node to the right-end node.)

Yes, I imagine that this doesn't work well. I mainly considered a 1-hop network during design.

(2) Improve the throughput of Lw-MAC. The original Lw-MAC only support one packet transmission and reception between a communication pair, in one wake-up period. In other words, for a sender, it can only send one packet to the receiver during receiver's wake-up period. If the sender has two packets for the receiver, it will have to use (receiver's) two cycles to transmit the two packets. To this end, I adopt the pending-bit scheme to allow kind of burst transmissions (by using the pending-bit embedded in the MAC header for instruction, buffered packets will be transmitted in a continuous sequence, back to back, to the receiver in one shot). This is similar to the continuous transmission scheme of T-MAC. :-)

This sounds like a really sensible (and easy) optimization! 🙂

Copy link
Member

@smlng smlng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check coding style and adapt as needed, specifically look for:

  • placement of parentheses
  • indention

check other comments, and address as you see fit - some are personal opinions so no need to adapt everything 😉

Otherwise nice work!

* latency and throughput!
*/
#ifndef LWMAC_WAKEUP_INTERVAL_US
#define LWMAC_WAKEUP_INTERVAL_US (100U * 1000)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use conversion macros US_PER_MS, here and below

* @brief The Maximum WR duration time.
*/
#ifndef LWMAC_PREAMBLE_DURATION_US
#define LWMAC_PREAMBLE_DURATION_US ((12*LWMAC_WAKEUP_INTERVAL_US)/10)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I admit I'm not into any details on this, but why times 12 and divide by 10, here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my knowledge, multiplying by 1.2 would result in an implicit cast to float which should be avoided. Integer division is enough.

#define A 15
#define B ((A*12)/10)
#define C (1.2 * A)

printf("A = %i, B = %i, C = %i\n", A, B, C);

results in A = 15, B = 18, C = 2147483640

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's however fixable by explicitly casting back to int like so:

#define D ((int)(1.2 * A))

I just check with my host compiler and it is equivalent to B, so B == D. This is even more readable I guess.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I didn't mean to suggest using * 1.2 here, I just wondered where this numbers to multiply and divide by come from. What's the rational to use these and not 42 and 13? Empirical results, random choice by dice, or logic?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empirical results, random choice by dice, or logic?

A bit all of them and poorly (i.e. not) documented. The idea was to send preambles/WRs for a slightly longer period than LWMAC_WAKEUP_INTERVAL_US in order to make sure that I will really be received by the destination. However, in retrospective I doubt this make much sense ... 😝

* dispatched to the driver.
*/
#ifndef LWMAC_WR_PREPARATION_US
#define LWMAC_WR_PREPARATION_US (7000U + LWMAC_WR_BEFORE_PHASE_US)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

above you #define LWMAC_TIME_BETWEEN_WR_US (7000U), so should/could(?) this actually be:

#define LWMAC_WR_PREPARATION_US (LWMAC_TIME_BETWEEN_WR_US + LWMAC_WR_BEFORE_PHASE_US)

Two further comments,

  • whats WR again? And,
  • you might think about consistent naming here, i.e. LWMAC_WR_<something>_US or LWMAC_<something>_WR_US, currently its a bit mixed up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WR is actually preamble, but is called "Wakeup Request, WR" in Lw-MAC.

* received at least one packet.
*/
#ifndef LWMAC_BROADCAST_DURATION_US
#define LWMAC_BROADCAST_DURATION_US ((LWMAC_WAKEUP_INTERVAL_US * 1100) / 1000)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again why 1100 and 1000? And can be reduced to *11 and / 10.


/**
* @brief CSMA retries for BROADCAST packet, too many may lead to running out of
* destinations wakup period.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/wakup/wakeup/

#define LOG_DEBUG(...) LOG(LOG_DEBUG, "[lwmac-rx] " __VA_ARGS__)

/* Break out of switch and mark the need for rescheduling */
#define GOTO_RX_STATE(rx_state, do_resched) gnrc_netdev2->rx.state = rx_state; \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have this inline, so I don't have to look it up every time to know whats happening

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what I see problematic here is, that it hides the break; statement which makes a difference to have or not in loops and switches. If you really want to use this I'd rename this to SET_RX_STATE_AND_BREAK to make it clear

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I acknowledge that hiding the break is bad, especially for the case where you might accidentally use it inside a loop.

I'd rather have this inline, so I don't have to look it up every time to know whats happening

Well, this is actually why you abstract stuff away into functions (or defines for that matter), so you need not know whats happening behind the scenes. In this case I'd see this as an implementation detail of the state machine implementation, so I don't like SET_RX_STATE_AND_BREAK too much.

Maybe we have a valid case for using a goto here, like so:

#define GOTO_RX_STATE(rx_state, do_resched) \
    gnrc_netdev2->rx.state = rx_state; \
    if(do_resched) goto rx_state_machine_begin; \
    else goto rx_state_machine_end

rx_state_machine_begin:
switch(rx.state)
{
// [...]
}
rx_state_machine_end:

What do you think? I don't like using goto too much either, but I've seen such an implementation sometimes. Probably the labels and switch statement should then also be wrapped inside macros.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mhm, I dislike goto even more, so maybe leave as is for now. Maybe someone else has an opinion on this, too.

*/

/* Send WA */
int res = gnrc_netdev2->send(gnrc_netdev2, pkt);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

res not used afterwards, rewrite to:

if (gnrc_netdev2->send(...) < 0) {

lwmac_packet_info_t info;
int ret = _parse_packet(pkt, &info);

if (ret != 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ret only used for debugging, could be omitted.


/* Sender maybe didn't get the WA */
if (info.header->type == FRAMETYPE_WR) {
LOG_INFO("Found a WR while waiting for DATA\n");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why LOG_INFO not LOG_DEBUG? or if problematic better use LOG_WARNING

{
if(gnrc_netdev2->lwmac.timeouts[i].type == TIMEOUT_DISABLED)
{
gnrc_netdev2->lwmac.timeouts[i].type = type;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coding style above and below, indention here

@zhuoshuguo
Copy link
Contributor Author

@smlng Thanks for the comments, and sorry for the mess! 😄 Will adapt soon!

@jnohlgard jnohlgard dismissed their stale review June 22, 2017 07:39

Unable to test

@smlng
Copy link
Member

smlng commented Jun 22, 2017

I don't see the point of having a complete (?) copy of examples/gnrc_networking to showcase lwmac while also having tests/lwmac. I'd rather extend gnrc_networking to allow lwmac as an option/alternative and keep its README as README.lwmac.md (or something) to described its usage and current limitations.

@zhuoshuguo
Copy link
Contributor Author

zhuoshuguo commented Jun 22, 2017

I don't see the point of having a complete (?) copy of examples/gnrc_networking to showcase lwmac while also having tests/lwmac. I'd rather extend gnrc_networking to allow lwmac as an option/alternative and keep its README as README.lwmac.md (or something) to described its usage and current limitations.

That's a good point~ What do you think? @emmanuelsearch @miri64 @kaspar030 . I do agree that there is some functionality overlap between examples/gnrc_networking_mac and tests/lwmac. So we remove tests/lwmac?

@smlng
Copy link
Member

smlng commented Jun 22, 2017

functionality overlap between examples/gnrc_networking_mac and tests/lwmac. So we remove tests/lwmac?

I'd rather do the opposite and remove the example. Because, I see the larger overlap between gnrc_networking_mac and the existing gnrc_networking, hence my suggestion to check the possibility to merge lwmac as an option into the gnrc_networking example.

@miri64
Copy link
Member

miri64 commented Jun 22, 2017

So we remove tests/lwmac?

@zhuoshuguo @smlng I would rather remove the example, if any.

Regarding integrating lwmac into gnrc_networking (speaking to @smlng now): this goes clearly against the initial thought of the examples: providing a concise example for one specific component. This is primarily to not overwhelm new users and allow them to pin-point, which component does what. In that sense gnrc_networking already violates that, I know (since it is a IPv6 router, a UDP client+server, a RPL node, and more in one). But there is no reason to make things even worse. If you want to know, why an example exists, please follow the discussion from #6554 (comment) onward.

@smlng
Copy link
Member

smlng commented Jun 22, 2017

@miri64 you're right: no need to bloat gnrc_networking any further.

Still I don't see the benefits of having a close copy of that example to show case lwmac - the test should do, and if currently does not: extend that, but remove the example.

@zhuoshuguo
Copy link
Contributor Author

zhuoshuguo commented Jun 22, 2017

Still I don't see the benefits of having a close copy of that example to show case lwmac

The origin goal for doing is to show that lwmac can support all the upper layers gnrc_networking have, which I believe is one of the most interesting (valuable) parts of lwmac (any MAC protocol).

@zhuoshuguo
Copy link
Contributor Author

So, we remove gnrc_networking_mac and extend tests/lwmac?

@miri64
Copy link
Member

miri64 commented Jun 22, 2017

The origin goal for doing is to show that lwmac can support all the upper layers gnrc_networking have, which I believe is one of the most interesting (valuable) parts of lwmac (any MAC protocol).

Is this something special for lwMAC or something that all MAC protocols should be expected to deliver due to the proper abstraction ;-)?

@zhuoshuguo
Copy link
Contributor Author

zhuoshuguo commented Jun 22, 2017

Is this something special for lwMAC or something that all MAC protocols should be expected to deliver due to the proper abstraction ;-)?

Em, for a MAC that is designed for specific purpose/usage (e.g., in WSN or IoT), it is not required to provide general support for upper layers. But, for (especially, duty-cycled) MAC protocols that aim to provide general support (the case of LWMAC), they should be able (expected) to deliver such capabilities.

@zhuoshuguo
Copy link
Contributor Author

If having gnrc_networking_mac now is still an issue worth more discussions, how about we handle it in the future?

So, now, we only keep tests/lwmac for basic tests (remove gnrc_networking_mac example), and go for the merge of lwmac, without getting stucked here?
How to integrate LWMAC with other networking applications/examples can be then addressed in following PR?

@zhuoshuguo
Copy link
Contributor Author

Ping?~

@smlng
Copy link
Member

smlng commented Jun 23, 2017

I will not block this, just because of the example - my objections are noted here, I think 😉 So please proceed as you see fit, we may cleanup up the examples/tests situation later on.

@zhuoshuguo
Copy link
Contributor Author

So please proceed as you see fit, we may cleanup up the examples/tests situation later on.

Yap!~ Thanks for the suggestion. :-)~ I will do that with all the other following updates of LWMAC and gnrc_mac module (like the timer source issues), in coming PRs.

So, we proceed? @miri64 @emmanuelsearch @kaspar030 @gebart ? :-)

@aabadie aabadie modified the milestone: Release 2017.07 Jun 23, 2017
@miri64
Copy link
Member

miri64 commented Jun 23, 2017

@smlng I would prefer if you hit the merge button ;-).

@zhuoshuguo
Copy link
Contributor Author

Ping~ @smlng Let's go for merge? :-)

@smlng
Copy link
Member

smlng commented Jun 26, 2017

OK, fingers crossed 🤞 😉

@smlng smlng merged commit 9ce9dd6 into RIOT-OS:master Jun 26, 2017
@zhuoshuguo
Copy link
Contributor Author

Congratulations!~ @daniel-k 😃 LWMAC finally gets merged.

And, @smlng @miri64 @kaspar030 @gebart Thanks a lot for all your hard work and time on this!~ 😄

@aabadie
Copy link
Contributor

aabadie commented Jun 26, 2017

Congrats @zhuoshuguo and other people involved in this PR!

@emmanuelsearch
Copy link
Member

Congrats @zhuoshuguo @daniel-k !

@daniel-k
Copy link
Member

Thank you all guys, especially @zhuoshuguo! 🎆

I'm really glad it got merged now. Sorry again for all the hard work testing and fixing stuff that I couldn't do anymore. If one day we meet in person, beer's on me 🍻

@JohannaOm
Copy link

Hello!
Is there a paper about LW-MAC that describes its functionality?
Thank You!

@areejeliyan
Copy link

Hi @benemorius, @zhuoshuguo and @miri64,
I have been trying to print out the achieved radio duty-cyle of LWMAC by setting the LWMAC_ENABLE_DUTYCYLE_RECORD flag in sys/include/net/gnrc/lwmac/types.h to "1". However, I am still unable to see the output on openmote-b. Can you please tell me what could be the problem?

@benemorius
Copy link
Member

@areejeliyan use the gnrc_networking_mac example and run the command mac duty.

See mac.c.

@areejeliyan
Copy link

Hi @benemorius,

I did and this is what I got. basically I can't see the duty cycle..
mac duty error
image

Another question: I am trying to build a protocol between 2 openmote-b that send and receive packet in lwmac.. is adding the USEMODULE += gnrc_lwmac module will guarantee that I am sending and receiving packets in lwmac. )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: network Area: Networking CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.