summaryrefslogtreecommitdiff
path: root/main.cpp
diff options
context:
space:
mode:
authorJesse Gilles <jgilles@multitech.com>2015-05-22 13:56:45 -0500
committerJesse Gilles <jgilles@multitech.com>2015-05-22 13:56:45 -0500
commit12eb2e9c901e9100e2fb938a64110263c24ea8e8 (patch)
tree001b5da0367b707e01232409530e814cea900161 /main.cpp
downloadlora-query-12eb2e9c901e9100e2fb938a64110263c24ea8e8.tar.gz
lora-query-12eb2e9c901e9100e2fb938a64110263c24ea8e8.tar.bz2
lora-query-12eb2e9c901e9100e2fb938a64110263c24ea8e8.zip
initial commit0.0.1
Diffstat (limited to 'main.cpp')
-rw-r--r--main.cpp303
1 files changed, 303 insertions, 0 deletions
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..106d918
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2015 by Multi-Tech Systems
+ *
+ * This file is part of lora-query.
+ *
+ * lora-query is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * lora-query is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with lora-query. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <mts/MTS_Text.h>
+#include <mts/MTS_Logger.h>
+#include <json/json.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sstream>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include "Version.h"
+
+#define INET_ADDR "127.0.0.1"
+#define INET_PORT 6677
+#define MAX_RECEIVED_BYTES 2000
+#define TIMEOUT 100 /* By default 100 msec */
+
+int get_stats = 0;
+int get_nodelist = 0;
+int get_json = 0;
+int timeout = TIMEOUT;
+const char* stats = "stats";
+const char* nodelist = "node list";
+const std::string lora_network_stats_json("/var/tmp/lora_network_stats.json");
+const std::string lora_network_nodelist("/var/tmp/lora_network_nodelist");
+const std::string lora_network_nodelist_json("/var/tmp/lora_network_nodelist.json");
+std::stringstream receiveStream;
+
+const int nodeSize = 15;
+const std::string NODE_ADDR("nodeAddr");
+const std::string NODE_DEV_EUI("devEui");
+const std::string NODE_JOINED("joined");
+const std::string NODE_SEQ_NUM("seqNum");
+const std::string NODE_PKTS_UP("pktsUp");
+const std::string NODE_PKTS_DOWN("pktsDown");
+const std::string NODE_PKTS_1ST("pkts1st");
+const std::string NODE_PKTS_2ND("pkts2nd");
+const std::string NODE_DROPPED("dropped");
+const std::string NODE_RSSI_MIN("rssiMin");
+const std::string NODE_RSSI_MAX("rssiMax");
+const std::string NODE_RSSI_AVR("rssiAvg");
+const std::string NODE_SNR_MIX("snrMin");
+const std::string NODE_SNR_MAX("snrMax");
+const std::string NODE_SNR_AVR("snrAvg");
+
+void getloraData(const char *command);
+void printStats(void);
+void printNodeList(void);
+void saveToFile(const std::string& fileName, const std::string& buffer);
+void parseOptions(int argc, char** argv);
+void printHelp(const std::string& sApp);
+std::string trim(std::string& str);
+
+int main(int argc, char**argv)
+{
+ parseOptions(argc, argv);
+
+ if (get_stats) {
+ getloraData(stats);
+ printStats();
+ }
+ if (get_nodelist) {
+ getloraData(nodelist);
+ if (get_json) {
+ printNodeList();
+ } else {
+ if (receiveStream.str().empty() ) {
+ return 0;
+ }
+ saveToFile(lora_network_nodelist, receiveStream.str());
+ std::cout << receiveStream.str();
+ }
+ }
+ return 0;
+}
+
+void getloraData(const char *command) {
+ int sockfd;
+ struct sockaddr_in servaddr;
+ int receiveBytes = 0;
+ char receiveMessage[MAX_RECEIVED_BYTES];
+ struct timeval tv;
+
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+
+ receiveStream.str("");
+ receiveStream.clear();
+
+ if (NULL == command) {
+ printError("Command is null\n");
+ return;
+ }
+
+ sockfd=socket(AF_INET,SOCK_DGRAM,0);
+ bzero(&servaddr,sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr=inet_addr(INET_ADDR);
+ servaddr.sin_port=htons(INET_PORT);
+ memset(receiveMessage, 0, MAX_RECEIVED_BYTES);
+
+ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+ printError("setsockopt error\n");
+ return;
+ }
+
+ sendto(sockfd, command, strlen(command), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
+
+ while(1) {
+ receiveBytes = recvfrom(sockfd, receiveMessage, MAX_RECEIVED_BYTES, 0, NULL, NULL);
+ if(receiveBytes < 0) {
+ /*printf("timeout\n");*/
+ break;
+ }
+ receiveStream << std::string(receiveMessage, receiveBytes);
+ }
+}
+
+void printStats() {
+ Json::Reader reader;
+ Json::Value stats;
+
+ if (receiveStream.str().empty() ) {
+ return;
+ }
+
+ if (!reader.parse(receiveStream.str(), stats), false) {
+ printError("Error parsing JSON: [%s]", receiveStream.str().c_str());
+ }
+
+ // Replace underscores keys with camel-case.
+ if (stats.isObject()) {
+ Json::Value::Members keys = stats.getMemberNames();
+ std::string newKey;
+ for (Json::Value::Members::iterator it = keys.begin(); it != keys.end(); ++it) {
+ const std::string& key = *it;
+ newKey.clear();
+ for (size_t i = 0; i < key.length() ; ++i) {
+ if (('_' == key[i]) || ('-' == key[i])) {
+ if ((i + 1) < key.length()) {
+ newKey.push_back(std::toupper(key[++i]));
+ }
+ } else {
+ newKey.push_back(key[i]);
+ }
+ }
+ stats[newKey] = stats[key];
+ stats.removeMember(key);
+ }
+ }
+ saveToFile(lora_network_stats_json, stats.toStyledString());
+ std::cout << stats.toStyledString();
+}
+
+void printNodeList() {
+ std::string line;
+ std::vector<std::string> parts;
+ Json::Value nodeList = Json::ValueType::arrayValue;
+
+ if (receiveStream.str().empty() ) {
+ return;
+ }
+
+ getline(receiveStream, line);
+ while (1) {
+ getline(receiveStream, line);
+ if (line.size() == 0)
+ break;
+
+ line = trim(line);
+ parts = MTS::Text::split(line, " ");
+
+ if (nodeSize == parts.size()) {
+ Json::Value jNode(Json::objectValue);
+ jNode[NODE_ADDR] = parts[0];
+ jNode[NODE_DEV_EUI] = parts[1];
+ jNode[NODE_JOINED] = parts[2];
+ jNode[NODE_SEQ_NUM] = atoi(parts[3].c_str());
+ jNode[NODE_PKTS_UP] = atoi(parts[4].c_str());
+ jNode[NODE_PKTS_DOWN] = atoi(parts[5].c_str());
+ jNode[NODE_PKTS_1ST] = atoi(parts[6].c_str());
+ jNode[NODE_PKTS_2ND] = atoi(parts[7].c_str());
+ jNode[NODE_DROPPED] = atoi(parts[8].c_str());
+ jNode[NODE_RSSI_MIN] = atoi(parts[9].c_str());
+ jNode[NODE_RSSI_MAX] = atoi(parts[10].c_str());
+ jNode[NODE_RSSI_AVR] = atoi(parts[11].c_str());
+ jNode[NODE_SNR_MIX] = atoi(parts[12].c_str());
+ jNode[NODE_SNR_MAX] = atoi(parts[13].c_str());
+ jNode[NODE_SNR_AVR] = atoi(parts[14].c_str());
+
+ nodeList.append(jNode);
+ }
+ else {
+ printError("Incorrect Node Data! parts.size() = [%d]\n", parts.size());
+ }
+ }
+ saveToFile(lora_network_nodelist_json, nodeList.toStyledString());
+ std::cout << nodeList.toStyledString();
+}
+
+void saveToFile(const std::string& fileName, const std::string& buffer) {
+ std::ofstream outFile;
+ outFile.open(fileName);
+ outFile << buffer;
+ outFile.close();
+}
+
+void parseOptions(int argc, char** argv) {
+
+ if(argc == 1) {
+ printHelp(argv[0]);
+ exit(0);
+ }
+
+ const char* short_options = "hvsnjt:";
+
+ const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {"stats", no_argument, 0, 's'},
+ {"node-list", no_argument, 0, 'n'},
+ {"json", no_argument, 0, 'j'},
+ {"timeout", required_argument, 0, 't'},
+ {0, 0, 0, 0}
+ };
+
+ int rez;
+ int option_index;
+
+ while ((rez=getopt_long(argc, argv, short_options, long_options, &option_index))!=-1) {
+ switch(rez){
+ case 's': {
+ ++get_stats;
+ break;
+ };
+ case 'n': {
+ ++get_nodelist;
+ break;
+ };
+ case 'j': {
+ ++get_json;
+ break;
+ };
+ case 't': {
+ timeout = atoi(optarg);
+ break;
+ }
+ case 'v':
+ printf("Version: %s\n", Version::version.c_str());
+ exit(0);
+ break;
+ case 'h':
+ case '?':
+ default: {
+ printHelp(argv[0]);
+ exit(0);
+ break;
+ };
+ };
+ };
+}
+
+void printHelp(const std::string& sApp) {
+ printf("Usage: %s [-t timeout] [-s] [-n]\n", sApp.c_str());
+ printf("\tSimple UDP client utility to pull info from LoRa Network server\n");
+ printf("\t--timeout (t) : UDP recv timeout, default: 100 (msecs)\n");
+ printf("\t--stats (s) : get LoRa Network server statistics\n");
+ printf("\t--node-list (n) : get Node List\n");
+ printf("\t--json (j) : data in json format\n");
+ printf("\t--help (?) : returns this message\n");
+ printf("\t--version (v) : print version\n");
+}
+
+std::string trim(std::string& str) {
+ str.erase(std::unique(str.begin(), str.end(), [](char a, char b) { return a == ' ' && b == ' '; } ), str.end() );
+ return str;
+}
+