/* Copyright 2016 Pascal Vizeli <[email protected]>
BSD License
https://github.com/pvizeli/CmdParser
*/
////
// This example is a demo for CmdCallback.
// It parse a command line and process callback function.
// This exemple is without Key Value parser function
////
#define ARDUINOJSON_ENABLE_STD_STREAM 1
#include "ArduinoJson.h"
#include "WString.h"
#include <CmdBuffer.hpp>
#include <CmdCallback.hpp>
#include <CmdParser.hpp>
#include <map>
#include <math.h>
char defaultHelp[] = "test";
template <size_t STORESIZE>
class CmdAdvCallback : public CmdCallback<STORESIZE> {
protected:
CmdParserString m_helpList[STORESIZE];
public:
CmdAdvCallback() {
for (size_t i = 0; i < STORESIZE; i++) {
m_helpList[i] = "test";
}
}
virtual ~CmdAdvCallback() {};
void help() {
Serial.println("Available commands:");
for (size_t i = 0; this->checkStorePos(i); i++) {
Serial.print("\t");
Serial.print(this->m_cmdList[i]);
Serial.print(" : ");
Serial.println(m_helpList[i]);
}
}
size_t getHelp(const CmdParserString*& cmdList, const CmdParserString*& helpList) {
cmdList = this->m_cmdList;
helpList = this->m_helpList;
if (this->m_nextElement >= STORESIZE) {
return STORESIZE;
}
return this->m_nextElement;
}
using CmdCallback<STORESIZE>::addCmd;
bool addCmd(CmdParserString cmdStr, CmdCallFunct cbFunct, CmdParserString helpMsg) {
// Store is full
if (this->m_nextElement >= STORESIZE) {
return false;
}
// add to store
m_helpList[this->m_nextElement] = helpMsg;
return this->addCmd(cmdStr, cbFunct);
}
void updateCmdProcessing(CmdParser * cmdParser,
CmdBufferObject *cmdBuffer,
Stream * serial)
{
// read data and check if command was entered
if (cmdBuffer->readSerialChar(serial)) {
Serial.println("received line");
// parse command line
if (cmdParser->parseCmd(cmdBuffer) != CMDPARSER_ERROR) {
// search command in store and call function
// ignore return value "false" if command was not found
if (!this->processCmd(cmdParser)) {
Serial.print("invalid command");
}
cmdBuffer->clear();
}
}
}
};
CmdAdvCallback<20> cmdCallback;
char strHallo[] = "HALLO";
char strQuit[] = "QUIT";
char strSet[] = "SET";
static const uint32_t JSON_DOC_SIZE = 1024;
void setup()
{
Serial.begin(115200);
cmdCallback.addCmd(strHallo, &functHallo);
cmdCallback.addCmd(strQuit, &functQuit, "");
cmdCallback.addCmd(strSet, &functSet, "");
cmdCallback.addCmd("setConfig", &functConfig, "Write config key as json, e.g. setConfig#cfg={\"device\":{\"location\":\"not_set\"}}");
cmdCallback.addCmd("help", &functHelp, "Print all available command and their help as JSON");
cmdCallback.addCmd("getEnum", &functEnum, "");
cmdCallback.addCmd("setCal", &functCalib, "");
Serial.println("Type you commands. Supported: ");
Serial.println("1: hallo");
Serial.println("2: set alarm on/off");
Serial.println("3: quit");
cmdCallback.help();
}
void loop()
{
static CmdBuffer<2048> myBuffer;
static CmdParser myParser;
// Set parser options
//...
myBuffer.setEcho(false);
myParser.setOptKeyValue(true);
myParser.setOptSeperator('#');
myParser.setOptIgnoreQuote(true);
// Auto Handling
//Serial.print("Recieved: ");
//Serial.println(myBuffer.getStringFromBuffer());
cmdCallback.updateCmdProcessing(&myParser, &myBuffer, &Serial);
//Serial.println(myBuffer.getStringFromBuffer());
// also possible manual with
// cmdCallback.processCmd(myParser);
}
void functHallo(CmdParser *myParser) {
Serial.println("Receive Hallo");
}
void functSet(CmdParser *myParser)
{
Serial.println("Receive Set");
// Alarm
if (myParser->equalCmdParam(1, "ALARM")) {
Serial.println(myParser->getCmdParam(2));
}
// Command Unknwon
else {
Serial.println("Only Alarm is allowed!");
}
}
void functQuit(CmdParser *myParser) {
Serial.println("Receive Quit");
}
// parse cfg settings like: setConfig#cfg={"device":{"location":"not_set","locationCode":"unknown","locationAccuracy":"99","nodeName":"ELOC_NONAME"},"config":{"secondsPerFile":60,"listenOnly":false,"cpuMaxFrequencyMHZ":80,"cpuMinFrequencyMHZ":10,"cpuEnableLightSleep":true,"bluetoothEnableAtStart":true,"bluetoothEnableOnTapping":true,"bluetoothEnableDuringRecord":true,"bluetoothOffTimeoutSeconds":60},"mic":{"MicType":"ns","MicBitShift":11,"MicSampleRate":20000,"MicUseAPLL":true,"MicUseTimingFix":true,"MicGPSCoords":"ns","MicPointingDirectionDegrees":"ns","MicHeight":"ns","MicMountType":"ns"}}
void functConfig(CmdParser *myParser) {
Serial.print("Size of parameter: ");
Serial.println(myParser->getParamCount());
for (int i = 0; i < myParser->getParamCount(); i++ ) {
Serial.print("para ");
Serial.print(i);
Serial.print(": ");
Serial.println(myParser->getCmdParam(i));
}
Serial.print("cfg set to ");
Serial.println(myParser->getValueFromKey("cfg"));
StaticJsonDocument<JSON_DOC_SIZE> doc;
DeserializationError error = deserializeJson(doc, myParser->getValueFromKey("cfg"));
if (error) {
Serial.println("Error while parsing json");
}
Serial.print("nodeName :");
String nodeName = doc["device"]["nodeName"];
Serial.println(nodeName);
Serial.print("location :");
Serial.print(doc["device"]["location"].as<const char*>() == NULL ? "null": "non null");
Serial.println(doc["device"]["location"].as<const char*>());
Serial.print("bluetoothOffTimeoutSeconds :");
int bluetoothOffTimeoutSeconds = doc["config"]["bluetoothOffTimeoutSeconds"];
Serial.println(bluetoothOffTimeoutSeconds);
Serial.print("bluetoothEnableDuringRecord :");
Serial.println(doc["config"]["bluetoothEnableDuringRecord"].as<bool>());
}
void functHelp(CmdParser *myParser) {
const CmdParserString* cmdStr;
const CmdParserString* helpMsg;
size_t numCmds = cmdCallback.getHelp(cmdStr, helpMsg);
Serial.println("get help");
StaticJsonDocument<256> doc;
JsonArray commands = doc.createNestedArray("commands");
for (int i = 0; i < numCmds; i++ ) {
JsonObject cmd = commands.createNestedObject();
cmd["cmd"] = cmdStr[i];
cmd["help"] = helpMsg[i];
}
String payload;
serializeJsonPretty(doc, payload);
Serial.println(payload);
StaticJsonDocument<2048> resp;
resp["ecode"] = 0;
resp["cmd"] = "help";
resp["payload"] = payload;
serializeJson(resp, Serial);
}
void addEnumToJson(JsonObject& object, int val, const char* name) {
// create an object
object["val"] = val;
object["state"] = name;
//return object;
}
#define ENUM_MACRO(name, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)\
enum class name { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 };\
constexpr const char *name##Strings[] = { #v1, #v2, #v3, #v4, #v5, #v6, #v7, #v8, #v9, #v10};\
template<typename T>\
constexpr const char *name##ToString(T value) { return name##Strings[static_cast<int>(value)]; }
/*
#define ENUM_MACRO(name, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)\
enum class name { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 };\
constexpr const char *name##Strings[] = { #v1, #v2, #v3, #v4, #v5, #v6, #v7, #v8, #v9, #v10};\
constexpr const char *toString(name value) {return name##Strings[static_cast<int>(value)]; }
*/
ENUM_MACRO(Esper, Unu, Du, Tri, Kvar, Kvin, Ses, Sep, Ok, Naux, Dek);
//constexpr const char * toString(Esper value){ return EsperStrings[static_cast<int>(value)]; }
void functEnum(CmdParser *myParser) {
String payload;
StaticJsonDocument<2048> resp;
resp["ecode"] = 0;
resp["cmd"] = "help";
Esper test = Esper::Naux;
Serial.print("enum: ");
//Serial.println(toString(test));
JsonObject object = resp.createNestedObject("payload");
addEnumToJson(object, static_cast<int>(test), EsperToString(test));
Esper test2 = Esper::Kvar;
Serial.print("enum2: ");
//Serial.println(toString(test2));
//resp["payload2"] = addEnumToJson(resp, static_cast<int>(test2), EsperToString(test2));
serializeJson(resp, Serial);
}
// measuredval : readVal
//setCal#cal={"3.2":3.5, "3.0":3.1}#val=3.1
void functCalib(CmdParser *myParser) {
Serial.print("cal set to ");
Serial.println(myParser->getValueFromKey("cal"));
Serial.print("val set to ");
float val = std::stof(myParser->getValueFromKey("val"));
Serial.println(val);
StaticJsonDocument<JSON_DOC_SIZE> doc;
DeserializationError error = deserializeJson(doc, myParser->getValueFromKey("cal"));
if (error) {
Serial.println("Error while parsing json");
}
JsonObject root = doc.as<JsonObject>();
std::map<float, float> calData;
for (JsonPair kv : root) {
Serial.println(kv.key().c_str());
Serial.println(kv.value().as<float>());
calData[std::stof(kv.key().c_str())] = kv.value().as<float>();
}
float loPoint = NAN;
float hiPoint = NAN;
float offset = 0;
float scale = 1.0;
for( std::map<float, float>::iterator iter = calData.begin(); iter != calData.end(); ++iter ) {
Serial.print(iter->first);
Serial.print(" : ");
Serial.println(iter->second);
if (iter->first < val) {
loPoint = iter->first;
offset =(iter->second - iter->first);
}
if (iter->first >= val) {
hiPoint = iter->first;
if (isnan(loPoint)) {
offset = (iter->second - iter->first);
}
else {
scale = (calData[hiPoint] - calData[loPoint]) / (hiPoint - loPoint);
offset = (iter->second - iter->first*scale);
}
break;
}
}
Serial.print("offset: ");
Serial.print(offset);
Serial.print(", scale: ");
Serial.println(scale);
float newVal = val * scale + offset;
Serial.print("newVal: ");
Serial.println(newVal);
}