CLI: enhance ping command (#211)
* Enhance ping command
* add Doxygen for timestamp in EchoReplyHandler
* fix function params name style
* use echo request containing timestamp instead of maintaining internal states
diff --git a/src/cli/README.md b/src/cli/README.md
index 27ce95a..890e8a5 100644
--- a/src/cli/README.md
+++ b/src/cli/README.md
@@ -348,13 +348,13 @@
Done
```
-### ping \<ipaddr\> [size]
+### ping \<ipaddr\> [size] [count] [interval]
Send an ICMPv6 Echo Request.
```bash
> ping fdde:ad00:beef:0:558:f56b:d688:799
-16 bytes from fdde:ad00:beef:0:558:f56b:d688:799: icmp_seq=1 hlim=64
+16 bytes from fdde:ad00:beef:0:558:f56b:d688:799: icmp_seq=1 hlim=64 time=28ms
```
### prefix add \<prefix\> [pvdcsr] [prf]
diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp
index e08c333..a25d70e 100644
--- a/src/cli/cli.cpp
+++ b/src/cli/cli.cpp
@@ -42,6 +42,7 @@
#include <platform/serial.h>
using Thread::Encoding::BigEndian::HostSwap16;
+using Thread::Encoding::BigEndian::HostSwap32;
namespace Thread {
namespace Cli {
@@ -83,6 +84,10 @@
Ip6::SockAddr Interpreter::sSockAddr;
Server *Interpreter::sServer;
uint8_t Interpreter::sEchoRequest[1500];
+uint16_t Interpreter::sLength = 8;
+uint16_t Interpreter::sCount = 1;
+uint32_t Interpreter::sInterval = 1000;
+Timer Interpreter::sPingTimer(&HandlePingTimer, NULL);
int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength)
{
@@ -557,6 +562,7 @@
void Interpreter::HandleEchoResponse(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
Ip6::IcmpHeader icmp6Header;
+ uint32_t timestamp = 0;
aMessage.Read(aMessage.GetOffset(), sizeof(icmp6Header), &icmp6Header);
@@ -570,26 +576,60 @@
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[5]),
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[6]),
HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[7]));
- sServer->OutputFormat(": icmp_seq=%d hlim=%d\r\n", icmp6Header.GetSequence(), aMessageInfo.mHopLimit);
+ sServer->OutputFormat(": icmp_seq=%d hlim=%d", icmp6Header.GetSequence(), aMessageInfo.mHopLimit);
+
+ if (aMessage.Read(aMessage.GetOffset() + sizeof(icmp6Header), sizeof(uint32_t), ×tamp) >= sizeof(uint32_t))
+ {
+ sServer->OutputFormat(" time=%dms", Timer::GetNow() - HostSwap32(timestamp));
+ }
+
+ sServer->OutputFormat("\r\n");
}
void Interpreter::ProcessPing(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
- long length = 8;
+ uint8_t index = 1;
+ long value;
VerifyOrExit(argc > 0, error = kThreadError_Parse);
+ VerifyOrExit(!sPingTimer.IsRunning(), error = kThreadError_Busy);
memset(&sSockAddr, 0, sizeof(sSockAddr));
SuccessOrExit(error = sSockAddr.GetAddress().FromString(argv[0]));
sSockAddr.mScopeId = 1;
- if (argc > 1)
+ sLength = 8;
+ sCount = 1;
+ sInterval = 1000;
+
+ while (index < argc)
{
- SuccessOrExit(error = ParseLong(argv[1], length));
+ SuccessOrExit(error = ParseLong(argv[index], value));
+
+ switch (index)
+ {
+ case 1:
+ sLength = (uint16_t)value;
+ break;
+
+ case 2:
+ sCount = (uint16_t)value;
+ break;
+
+ case 3:
+ sInterval = (uint32_t)value;
+ sInterval = sInterval * 1000;
+ break;
+
+ default:
+ ExitNow(error = kThreadError_Parse);
+ }
+
+ index++;
}
- sIcmpEcho.SendEchoRequest(sSockAddr, sEchoRequest, length);
+ HandlePingTimer(NULL);
return;
@@ -597,6 +637,18 @@
AppendResult(error);
}
+void Interpreter::HandlePingTimer(void *aContext)
+{
+ *(uint32_t *)sEchoRequest = HostSwap32(Timer::GetNow());
+ sIcmpEcho.SendEchoRequest(sSockAddr, sEchoRequest, sLength);
+ sCount--;
+
+ if (sCount)
+ {
+ sPingTimer.Start(sInterval);
+ }
+}
+
ThreadError Interpreter::ProcessPrefixAdd(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp
index 113608d..a6afc29 100644
--- a/src/cli/cli.hpp
+++ b/src/cli/cli.hpp
@@ -38,6 +38,7 @@
#include <cli/cli_server.hpp>
#include <net/icmp6.hpp>
+#include <common/timer.hpp>
namespace Thread {
@@ -120,6 +121,7 @@
static void ProcessWhitelist(int argc, char *argv[]);
static void HandleEchoResponse(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
+ static void HandlePingTimer(void *aContext);
static void HandleActiveScanResult(otActiveScanResult *aResult);
static int Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength);
static ThreadError ParseLong(char *argv, long &value);
@@ -131,6 +133,10 @@
static Ip6::IcmpEcho sIcmpEcho;
static Server *sServer;
static uint8_t sEchoRequest[];
+ static uint16_t sLength;
+ static uint16_t sCount;
+ static uint32_t sInterval;
+ static Timer sPingTimer;
};
} // namespace Cli