From 12eb2e9c901e9100e2fb938a64110263c24ea8e8 Mon Sep 17 00:00:00 2001 From: Jesse Gilles Date: Fri, 22 May 2015 13:56:45 -0500 Subject: initial commit --- main.cpp | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 main.cpp (limited to 'main.cpp') 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 . + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 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; +} + -- cgit v1.2.3