Clean up CoAP CLI. (#1864)

- Change static methods into class methods.
- Remove client/server distinction.
- Fix callback method types and remove unnecessary type casts.
- Update README.md to reflect changes.
This commit is contained in:
Jonathan Hui
2017-06-02 08:56:47 -07:00
committed by GitHub
parent 08e352ca3e
commit 8872e292eb
5 changed files with 140 additions and 193 deletions
+36 -34
View File
@@ -14,7 +14,7 @@ OpenThread test scripts use the CLI to execute test cases.
* [child](#child-list)
* [childmax](#childmax)
* [childtimeout](#childtimeout)
* [coap](#coap-server-phase)
* [coap](#coap-start)
* [commissioner](#commissioner-start-provisioningurl)
* [contextreusedelay](#contextreusedelay)
* [counter](#counter)
@@ -271,55 +271,57 @@ Set the Thread Child Timeout value.
Done
```
### coap server \<phase\>
### coap start
Starts and stops the simple CoAP server.
* phase: Either "start" or "stop" the server.
Starts the application coap service.
```bash
> coap server start
Server started with resource '': Done
> coap server stop
Server stopped: Done
> coap start
Coap service started: Done
```
### coap server name \[URI\]
### coap stop
Outputs the currently used URI String of the CoAP resource.
* URI: If provided the URI String will be changed to the new value.
Stops the application coap service.
```bash
> coap server name
Current resource name is '': Done
> coap server name test
Changing resource name to 'test': Done
> coap start
Coap service stopped: Done
```
### coap client \<method\> \<IPv6address\> \<URI\> \[payload\] \[messageType\]
### coap resource \[uri-path\]
Simple CoAP client that can send Non-/Confirmable GET/PUT/POST/DELETE messages.
Sets the URI-Path for the test resource.
```bash
> coap resource test
Resource name is 'test': Done
> coap resource
Resource name is 'test': Done
```
### coap \<method\> \<address\> \<uri\> \[payload\] \[type\]
* method: CoAP method to be used (GET/PUT/POST/DELETE).
* IPv6address: IP address of the CoAP server to query.
* URI: URI String of the resource on the CoAP server.
* address: IP address of the CoAP server to query.
* uri: URI String of the resource on the CoAP server.
* payload: In case of PUT/POST/DELETE a payload can be encapsulated.
* messageType: Switch between confirmable ("con") and non-confirmable (default).
* type: Switch between confirmable ("con") and non-confirmable (default).
```bash
> coap client get fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc test
Sending CoAP message: Done
Received CoAP request from [fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc]: GET
CoAP response sent successfully!
Received CoAP response with payload: 30
> coap client put fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc test non-con somePayload
Sending CoAP message: Done
> coap client put fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc test con 123
Sending CoAP message: Done
Received CoAP request from [fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc]: PUT with payload: ba 00 00 20
CoAP response sent successfully!
Received CoAP response
> coap get fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc test
Sending coap message: Done
Received coap request from [fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc]: GET
coap response sent successfully!
Received coap response with payload: 30
> coap put fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc test non-con somePayload
Sending coap message: Done
Received coap request from [fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc]: PUT with payload: 73 6f 6d 65 50 61 79 6c 6f 61 64
> coap put fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc test con 123
Sending coap message: Done
Received coap request from [fdde:ad00:beef:0:dbaa:f1d0:8afb:30dc]: PUT with payload: 31 32 33
coap response sent successfully!
Received coap response
```
### commissioner start \<provisioningUrl\>
+6 -3
View File
@@ -223,6 +223,9 @@ typedef otPtr<const uint8_t> otBufferPtr;
typedef otPtr<const char> otStringPtr;
Interpreter::Interpreter(otInstance *aInstance):
#if OPENTHREAD_ENABLE_APPLICATION_COAP
mCoap(*this),
#endif
mServer(NULL),
#ifdef OTDLL
mApiInstance(otApiInit()),
@@ -313,7 +316,7 @@ int Interpreter::Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength)
return static_cast<int>(cur - aBin);
}
void Interpreter::AppendResult(otError aError)
void Interpreter::AppendResult(otError aError) const
{
if (aError == OT_ERROR_NONE)
{
@@ -325,7 +328,7 @@ void Interpreter::AppendResult(otError aError)
}
}
void Interpreter::OutputBytes(const uint8_t *aBytes, uint8_t aLength)
void Interpreter::OutputBytes(const uint8_t *aBytes, uint8_t aLength) const
{
for (int i = 0; i < aLength; i++)
{
@@ -657,7 +660,7 @@ exit:
void Interpreter::ProcessCoap(int argc, char *argv[])
{
otError error;
error = Coap::Process(mInstance, argc, argv, *mServer);
error = mCoap.Process(argc, argv);
AppendResult(error);
}
+11 -2
View File
@@ -50,6 +50,7 @@
#if OPENTHREAD_ENABLE_APPLICATION_COAP
#include <coap/coap_header.hpp>
#include "cli/cli_coap.hpp"
#endif
#include "common/code_utils.hpp"
@@ -94,6 +95,8 @@ struct Command
*/
class Interpreter
{
friend class Coap;
public:
/**
@@ -156,8 +159,8 @@ private:
kDefaultJoinerTimeout = 120, ///< Default timeout for Joiners, in seconds.
};
void AppendResult(otError error);
void OutputBytes(const uint8_t *aBytes, uint8_t aLength);
void AppendResult(otError error) const;
void OutputBytes(const uint8_t *aBytes, uint8_t aLength) const;
void ProcessHelp(int argc, char *argv[]);
void ProcessAutoStart(int argc, char *argv[]);
@@ -321,6 +324,12 @@ private:
void HandleDnsResponse(const char *aHostname, Ip6::Address &aAddress, uint32_t aTtl, otError aResult);
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP
Coap mCoap;
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
static const struct Command sCommands[];
Server *mServer;
+59 -121
View File
@@ -28,7 +28,7 @@
/**
* @file
* This file implements a simple CLI coap server and client.
* This file implements a simple CLI for the CoAP service.
*/
#ifdef OPENTHREAD_CONFIG_FILE
@@ -49,18 +49,7 @@
namespace ot {
namespace Cli {
const CoapCommand Coap::sCommands[] =
{
{ "client", &ProcessClient },
{ "server", &ProcessServer }
};
Server *Coap::sServer;
otCoapResource Coap::sResource;
otInstance *Coap::sInstance;
char Coap::sUriPath[kMaxUriLength];
void Coap::PrintPayload(otMessage *aMessage)
void Coap::PrintPayload(otMessage *aMessage) const
{
uint8_t buf[kMaxBufferSize];
uint16_t bytesToPrint;
@@ -69,115 +58,70 @@ void Coap::PrintPayload(otMessage *aMessage)
if (length > 0)
{
sServer->OutputFormat(" with payload: ");
mInterpreter.mServer->OutputFormat(" with payload: ");
while (length > 0)
{
bytesToPrint = (length < sizeof(buf)) ? length : sizeof(buf);
otMessageRead(aMessage, otMessageGetOffset(aMessage) + bytesPrinted, buf, bytesToPrint);
OutputBytes(buf, static_cast<uint8_t>(bytesToPrint));
mInterpreter.OutputBytes(buf, static_cast<uint8_t>(bytesToPrint));
length -= bytesToPrint;
bytesPrinted += bytesToPrint;
}
}
sServer->OutputFormat("\r\n");
mInterpreter.mServer->OutputFormat("\r\n");
}
void Coap::ConvertToLower(char *aString)
{
uint8_t i = 0;
while (aString[i])
{
aString[i] = (char)tolower(aString[i]);
i++;
}
}
void Coap::OutputBytes(const uint8_t *aBytes, uint8_t aLength)
{
for (int i = 0; i < aLength; i++)
{
sServer->OutputFormat("%02x ", aBytes[i]);
}
}
otError Coap::Process(otInstance *aInstance, int argc, char *argv[], Server &aServer)
{
otError error = OT_ERROR_NONE;
sInstance = aInstance;
sServer = &aServer;
sResource.mUriPath = sUriPath;
sResource.mContext = aInstance;
sResource.mHandler = (otCoapRequestHandler) &Coap::s_HandleServerResponse;
VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);
for (unsigned int i = 0; i < sizeof(sCommands) / sizeof(sCommands[0]); i++)
{
if (strcmp(argv[0], sCommands[i].mName) == 0)
{
error = sCommands[i].mCommand(argc - 1, argv + 1);
break;
}
}
exit:
return error;
}
otError Coap::ProcessServer(int argc, char *argv[])
otError Coap::Process(int argc, char *argv[])
{
otError error = OT_ERROR_NONE;
VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);
ConvertToLower(argv[0]);
if (strcmp(argv[0], "start") == 0)
{
SuccessOrExit(error = otCoapStart(sInstance, OT_DEFAULT_COAP_PORT));
SuccessOrExit(error = otCoapAddResource(sInstance, &sResource));
sServer->OutputFormat("Server started with resource '%s': ", sResource.mUriPath);
SuccessOrExit(error = otCoapStart(mInterpreter.mInstance, OT_DEFAULT_COAP_PORT));
mInterpreter.mServer->OutputFormat("Coap service started: ");
}
else if (strcmp(argv[0], "stop") == 0)
{
otCoapRemoveResource(sInstance, &sResource);
SuccessOrExit(error = otCoapStop(sInstance));
sServer->OutputFormat("Server stopped: ");
otCoapRemoveResource(mInterpreter.mInstance, &mResource);
SuccessOrExit(error = otCoapStop(mInterpreter.mInstance));
mInterpreter.mServer->OutputFormat("Coap service stopped: ");
}
else if (strcmp(argv[0], "name") == 0)
else if (strcmp(argv[0], "resource") == 0)
{
mResource.mUriPath = mUriPath;
mResource.mContext = this;
mResource.mHandler = &Coap::HandleServerResponse;
if (argc > 1)
{
strlcpy(sUriPath, argv[1], kMaxUriLength);
sServer->OutputFormat("Changing resource name to '%s': ", sResource.mUriPath);
}
else
{
sServer->OutputFormat("Current resource name is '%s': ", sResource.mUriPath);
strlcpy(mUriPath, argv[1], kMaxUriLength);
SuccessOrExit(error = otCoapAddResource(mInterpreter.mInstance, &mResource));
}
mInterpreter.mServer->OutputFormat("Resource name is '%s': ", mResource.mUriPath);
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
error = ProcessRequest(argc, argv);
}
exit:
return error;
}
void OTCALL Coap::s_HandleServerResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,
otMessageInfo *aMessageInfo)
void OTCALL Coap::HandleServerResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,
const otMessageInfo *aMessageInfo)
{
static_cast<Coap *>(aContext)->HandleServerResponse(aHeader, aMessage, aMessageInfo);
}
void Coap::HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, otMessageInfo *aMessageInfo)
void Coap::HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
otError error = OT_ERROR_NONE;
otCoapHeader responseHeader;
@@ -185,36 +129,36 @@ void Coap::HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, otMe
otCoapCode responseCode = OT_COAP_CODE_EMPTY;
char responseContent = '0';
sServer->OutputFormat("Received CoAP request from [%x:%x:%x:%x:%x:%x:%x:%x]: ",
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[0]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[1]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[2]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[3]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[4]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[5]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[6]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[7]));
mInterpreter.mServer->OutputFormat("Received coap request from [%x:%x:%x:%x:%x:%x:%x:%x]: ",
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[0]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[1]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[2]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[3]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[4]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[5]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[6]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[7]));
switch (otCoapHeaderGetCode(aHeader))
{
case OT_COAP_CODE_GET:
sServer->OutputFormat("GET");
mInterpreter.mServer->OutputFormat("GET");
break;
case OT_COAP_CODE_DELETE:
sServer->OutputFormat("DELETE");
mInterpreter.mServer->OutputFormat("DELETE");
break;
case OT_COAP_CODE_PUT:
sServer->OutputFormat("PUT");
mInterpreter.mServer->OutputFormat("PUT");
break;
case OT_COAP_CODE_POST:
sServer->OutputFormat("POST");
mInterpreter.mServer->OutputFormat("POST");
break;
default:
sServer->OutputFormat("Undefined\r\n");
mInterpreter.mServer->OutputFormat("Undefined\r\n");
return;
}
@@ -240,7 +184,7 @@ void Coap::HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, otMe
otCoapHeaderSetPayloadMarker(&responseHeader);
}
responseMessage = otCoapNewMessage(sInstance, &responseHeader);
responseMessage = otCoapNewMessage(mInterpreter.mInstance, &responseHeader);
VerifyOrExit(responseMessage != NULL, error = OT_ERROR_NO_BUFS);
if (otCoapHeaderGetCode(aHeader) == OT_COAP_CODE_GET)
@@ -248,26 +192,24 @@ void Coap::HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, otMe
SuccessOrExit(error = otMessageAppend(responseMessage, &responseContent, sizeof(responseContent)));
}
SuccessOrExit(error = otCoapSendResponse(sInstance, responseMessage, aMessageInfo));
SuccessOrExit(error = otCoapSendResponse(mInterpreter.mInstance, responseMessage, aMessageInfo));
}
exit:
if (error != OT_ERROR_NONE && responseMessage != NULL)
{
sServer->OutputFormat("Cannot send CoAP response message: Error %d\r\n", error);
mInterpreter.mServer->OutputFormat("Cannot send coap response message: Error %d: %s\r\n",
error, otThreadErrorToString(error));
otMessageFree(responseMessage);
}
else
else if (responseCode >= OT_COAP_CODE_RESPONSE_MIN)
{
if (responseCode >= OT_COAP_CODE_RESPONSE_MIN)
{
sServer->OutputFormat("CoAP response sent successfully!\r\n");
}
mInterpreter.mServer->OutputFormat("coap response sent successfully!\r\n");
}
}
otError Coap::ProcessClient(int argc, char *argv[])
otError Coap::ProcessRequest(int argc, char *argv[])
{
otError error = OT_ERROR_NONE;
otMessage *message = NULL;
@@ -284,8 +226,6 @@ otError Coap::ProcessClient(int argc, char *argv[])
VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);
// CoAP-Code
ConvertToLower(argv[0]);
if (strcmp(argv[0], "get") == 0)
{
coapCode = OT_COAP_CODE_GET;
@@ -330,8 +270,6 @@ otError Coap::ProcessClient(int argc, char *argv[])
// CoAP-Type
if (argc > 3)
{
ConvertToLower(argv[3]);
if (strcmp(argv[3], "con") == 0)
{
coapType = OT_COAP_TYPE_CONFIRMABLE;
@@ -352,7 +290,7 @@ otError Coap::ProcessClient(int argc, char *argv[])
}
}
message = otCoapNewMessage(sInstance, &header);
message = otCoapNewMessage(mInterpreter.mInstance, &header);
VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
// Embed content into message if given
@@ -366,17 +304,16 @@ otError Coap::ProcessClient(int argc, char *argv[])
messageInfo.mPeerPort = OT_DEFAULT_COAP_PORT;
messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || coapCode == OT_COAP_CODE_GET)
if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (coapCode == OT_COAP_CODE_GET))
{
error = otCoapSendRequest(sInstance, message, &messageInfo,
(otCoapResponseHandler) &Coap::s_HandleClientResponse, NULL);
error = otCoapSendRequest(mInterpreter.mInstance, message, &messageInfo, &Coap::HandleClientResponse, this);
}
else
{
error = otCoapSendRequest(sInstance, message, &messageInfo, NULL, NULL);
error = otCoapSendRequest(mInterpreter.mInstance, message, &messageInfo, NULL, NULL);
}
sServer->OutputFormat("Sending CoAP message: ");
mInterpreter.mServer->OutputFormat("Sending coap request: ");
exit:
@@ -388,22 +325,23 @@ exit:
return error;
}
void OTCALL Coap::s_HandleClientResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,
otMessageInfo *aMessageInfo, otError aResult)
void OTCALL Coap::HandleClientResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,
const otMessageInfo *aMessageInfo, otError aError)
{
static_cast<Coap *>(aContext)->HandleClientResponse(aHeader, aMessage, aMessageInfo, aResult);
static_cast<Coap *>(aContext)->HandleClientResponse(aHeader, aMessage, aMessageInfo, aError);
}
void Coap::HandleClientResponse(otCoapHeader *aHeader, otMessage *aMessage, otMessageInfo *aMessageInfo,
otError aResult)
void Coap::HandleClientResponse(otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo,
otError aError)
{
if (aResult != OT_ERROR_NONE)
if (aError != OT_ERROR_NONE)
{
sServer->OutputFormat("Error receiving CoAP response message: %d\r\n", aResult);
mInterpreter.mServer->OutputFormat("Error receiving coap response message: Error %d: %s\r\n",
aError, otThreadErrorToString(aError));
}
else
{
sServer->OutputFormat("Received CoAP response");
mInterpreter.mServer->OutputFormat("Received coap response");
PrintPayload(aMessage);
}
+28 -33
View File
@@ -36,21 +36,12 @@
#include <openthread/types.h>
#include "cli/cli.hpp"
#include "coap/coap_header.hpp"
namespace ot {
namespace Cli {
/**
* This structure represents a CLI command.
*
*/
struct CoapCommand
{
const char *mName; ///< A pointer to the command string.
otError(*mCommand)(int argc, char *argv[]); ///< A function pointer to process the command.
};
class Interpreter;
/**
* This class implements the CLI CoAP server and client.
@@ -60,15 +51,21 @@ class Coap
{
public:
/**
* This method interprets a list of CLI arguments.
* Constructor
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] argc The number of elements in argv.
* @param[in] argv A pointer to an array of command line arguments.
* @param[in] aServer A reference to the CLI server.
* @param[in] aInterpreter The CLI interpreter.
*
*/
static otError Process(otInstance *aInstance, int argc, char *argv[], Server &aServer);
Coap(Interpreter &aInterpreter): mInterpreter(aInterpreter) { }
/**
* This method interprets a list of CLI arguments.
*
* @param[in] argc The number of elements in argv.
* @param[in] argv A pointer to an array of command line arguments.
*
*/
otError Process(int argc, char *argv[]);
private:
enum
@@ -76,26 +73,24 @@ private:
kMaxUriLength = 32,
kMaxBufferSize = 16
};
static void PrintPayload(otMessage *aMessage);
static void ConvertToLower(char *aString);
static void OutputBytes(const uint8_t *aBytes, uint8_t aLength);
static otError ProcessClient(int argc, char *argv[]);
static otError ProcessServer(int argc, char *argv[]);
void PrintPayload(otMessage *aMessage) const;
static void OTCALL s_HandleServerResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,
otMessageInfo *aMessageInfo);
static void HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, otMessageInfo *aMessageInfo);
static void OTCALL s_HandleClientResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,
otMessageInfo *aMessageInfo, otError aResult);
static void HandleClientResponse(otCoapHeader *aHeader, otMessage *aMessage, otMessageInfo *aMessageInfo,
otError aResult);
otError ProcessRequest(int argc, char *argv[]);
static const CoapCommand sCommands[];
static Server *sServer;
static otCoapResource sResource;
static otInstance *sInstance;
static char sUriPath[kMaxUriLength];
static void OTCALL HandleServerResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,
const otMessageInfo *aMessageInfo);
void HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo);
static void OTCALL HandleClientResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage,
const otMessageInfo *aMessageInfo, otError aError);
void HandleClientResponse(otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo,
otError aError);
otCoapResource mResource;
char mUriPath[kMaxUriLength];
Interpreter &mInterpreter;
};
} // namespace Cli