summaryrefslogtreecommitdiff
path: root/loragw_pkt_logger
diff options
context:
space:
mode:
Diffstat (limited to 'loragw_pkt_logger')
-rw-r--r--loragw_pkt_logger/LICENSE.TXT49
-rw-r--r--loragw_pkt_logger/Makefile40
-rw-r--r--loragw_pkt_logger/README88
-rw-r--r--loragw_pkt_logger/global_conf.json46
-rw-r--r--loragw_pkt_logger/inc/parson.h100
-rw-r--r--loragw_pkt_logger/local_conf.json5
-rw-r--r--loragw_pkt_logger/obj/.gitkeep0
-rw-r--r--loragw_pkt_logger/src/loragw_pkt_logger.c566
-rw-r--r--loragw_pkt_logger/src/parson.c649
9 files changed, 0 insertions, 1543 deletions
diff --git a/loragw_pkt_logger/LICENSE.TXT b/loragw_pkt_logger/LICENSE.TXT
deleted file mode 100644
index 2007c51..0000000
--- a/loragw_pkt_logger/LICENSE.TXT
+++ /dev/null
@@ -1,49 +0,0 @@
---- For the parson library (parson.c and parson.h) ---
-
- Parson ( http://kgabis.github.com/parson/ )
- Copyright (c) 2012 Krzysztof Gabis
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-
- --- For the rest of the code : Revised BSD License ---
-
-Copyright (c) 2013, SEMTECH S.A.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the Semtech corporation nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/loragw_pkt_logger/Makefile b/loragw_pkt_logger/Makefile
deleted file mode 100644
index 8946c5b..0000000
--- a/loragw_pkt_logger/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-### Application-specific constants
-
-APP_NAME=loragw_pkt_logger
-
-### constant symbols
-CROSS_COMPILE=
-CC=gcc
-CFLAGS=-O2 -Wall -Wextra -Iinc
-C99FLAGS=-O2 -Wall -Wextra -std=c99 -Iinc
-FLAG_AUX=
-
-### constants for Lora Gateway HAL library
-
-LGW_PATH=../libloragw
-LGW_INC=-I$(LGW_PATH)/inc
-
-LGW_LNK=-lloragw -lrt -lmpsse
-#LGW_LNK=-lloragw -lrt
-# add libmpsse or not, depending on what option you compiled the libloragw with
-
-### general build targets
-
-all: $(APP_NAME)
-
-clean:
- rm -f obj/*.o
- rm -f $(APP_NAME)
-
-### sub-modules compilation
-
-obj/parson.o: src/parson.c
- $(CROSS_COMPILE)$(CC) -c $(C99FLAGS) -o obj/parson.o $(LGW_INC) src/parson.c $(FLAG_AUX)
-
-### main program compilation and assembly
-
-obj/$(APP_NAME).o: src/$(APP_NAME).c
- $(CROSS_COMPILE)$(CC) -c $(C99FLAGS) -o obj/$(APP_NAME).o $(LGW_INC) src/$(APP_NAME).c $(FLAG_AUX)
-
-$(APP_NAME): $(LGW_PATH)/libloragw.a obj/$(APP_NAME).o obj/parson.o
- $(CROSS_COMPILE)$(CC) -o $(APP_NAME) obj/$(APP_NAME).o obj/parson.o -L$(LGW_PATH) $(LGW_LNK)
diff --git a/loragw_pkt_logger/README b/loragw_pkt_logger/README
deleted file mode 100644
index 9469904..0000000
--- a/loragw_pkt_logger/README
+++ /dev/null
@@ -1,88 +0,0 @@
- / _____) _ | |
- ( (____ _____ ____ _| |_ _____ ____| |__
- \____ \| ___ | (_ _) ___ |/ ___) _ \
- _____) ) ____| | | || |_| ____( (___| | | |
- (______/|_____)_|_|_| \__)_____)\____)_| |_|
- ©2013 Semtech-Cycleo
-
-Lora Gateway packet logger
-===========================
-
-1. Introduction
-----------------
-
-This software is used to set up a Lora concentrator using a JSON configuration
-file and then record all the packets received in a log file, indefinitely, until
-the user stops the application.
-No filtering is done and all packets that are Lora packets with the correct RF
-parameters (frequency, datarate, bandwidth) should appear in the log.
-
-2. Dependencies
-----------------
-
-This program uses the Parson library (http://kgabis.github.com/parson/) by
-Krzysztof Gabis for JSON parsing.
-Many thanks to him for that very practical and well written library.
-
-This program is a typical example of Lora Gateway HAL usage for receiving
-packets.
-
-Only high-level functions are used (the ones contained in loragw_hal) so there
-is no hardware dependencies assuming the HAL is matched with the proper version
-of the hardware.
-Data structures of the received packets are accessed by name (ie. not at a
-binary level) so new functionalities can be added to the API without affecting
-that program at all.
-
-It was tested with v1.0.0 of the libloragw library, and should be compatible
-with any later version of the library assuming the API is downward-compatible.
-
-3. Usage
----------
-
-To stop the application, press Ctrl+C.
-
-The only optional parameter when launching the application is the log rotation
-time (in seconds).
-
-The way the program takes configuration files into account is the following:
- * if there is a debug_conf.json parse it, others are ignored
- * if there is a global_conf.json parse it, look for the next file
- * if there is a local_conf.json parse it
-If some parameters are defined in both global and local configuration files, the
-local definition overwrites the global definition.
-
-The global configuration file should be exactly the same throughout your
-network, contain all global parameters (parameters for "sensor" radio channels)
-and preferably default "safe" values for parameters that are specific for each
-gateway (eg. specify a default MAC address).
-
-The local configuration file should contain parameters that are specific to each
-gateway (eg. MAC address, frequency for backhaul radio channels).
-
-In each configuration file, the program looks for a JSON object named
-"SX1301_conf" that should contain the parameters for the Lora concentrator board
-(RF channels definition, modem parameters, etc) and another JSON object called
-"gateway_conf" that should contain the gateway parameters (gateway MAC address,
-IP address of the Lora MAC controller, network authentication parameters, etc).
-
-To learn more about the JSON configuration format, read the provided JSON files
-and the API documentation. A dedicated document will be available later on.
-
-The received packets are put in a CSV file whose name include the MAC address of
-the gateway in hexadecimal format and a UTC timestamp of log starting time in
-ISO 8601 recommended compact format:
-yyyymmddThhmmssZ (eg. 20131009T172345Z for October 9th, 2013 at 5:23:45PM UTC)
-
-To able continuous monitoring, the current log file is closed is closed and a
-new one is opened every hour (by default, rotation interval is settable by the
-user using -r command line option).
-No packet is lost during that rotation of log file.
-Every log file but the current one can then be modified, uploaded and/or deleted
-without any consequence for the program execution.
-
-4. Changelog
--------------
-
-2013-10-24, v1
-Initial version.
diff --git a/loragw_pkt_logger/global_conf.json b/loragw_pkt_logger/global_conf.json
deleted file mode 100644
index 6bc8f06..0000000
--- a/loragw_pkt_logger/global_conf.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "SX1301_conf": {
- "radio_0": {
- "enable": true,
- "freq": 868200000
- },
- "chan_multiSF_0": {
- "enable": true,
- "radio": 0,
- "if": -100000,
- "note": "Lora MAC channel, 125kHz, all SF, 868.1 MHz"
- },
- "chan_multiSF_1": {
- "enable": true,
- "radio": 0,
- "if": 100000,
- "note": "Lora MAC channel, 125kHz, all SF, 868.3 MHz"
- },
- "chan_multiSF_2": {
- "enable": true,
- "radio": 0,
- "if": 300000,
- "note": "Lora MAC channel, 125kHz, all SF, 868.5 MHz"
- },
- "chan_Lora_std": {
- "enable": true,
- "radio": 0,
- "if": 100000,
- "bandwidth": 250000,
- "spread_factor": 7,
- "note": "Lora MAC channel, 250kHz, SF7, 868.3 MHz"
- },
-
- "chan_FSK": {
- "enable": true,
- "radio": 0,
- "if": 100000,
- "bandwidth": 250000,
- "datarate": 100000,
- "note": "FSK 100kbps channel, 868.3 MHz"
- }
- },
- "gateway_conf": {
- "gateway_ID": "AA555A0000000000"
- }
-}
diff --git a/loragw_pkt_logger/inc/parson.h b/loragw_pkt_logger/inc/parson.h
deleted file mode 100644
index 00728b1..0000000
--- a/loragw_pkt_logger/inc/parson.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- Parson ( http://kgabis.github.com/parson/ )
- Copyright (c) 2012 Krzysztof Gabis
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-*/
-
-#ifndef parson_parson_h
-#define parson_parson_h
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#include <stddef.h> /* size_t */
-
-/* Types and enums */
-typedef struct json_object_t JSON_Object;
-typedef struct json_array_t JSON_Array;
-typedef struct json_value_t JSON_Value;
-
-typedef enum json_value_type {
- JSONError = 0,
- JSONNull = 1,
- JSONString = 2,
- JSONNumber = 3,
- JSONObject = 4,
- JSONArray = 5,
- JSONBoolean = 6
-} JSON_Value_Type;
-
-/* Parses first JSON value in a file, returns NULL in case of error */
-JSON_Value * json_parse_file(const char *filename);
-
-/* Parses first JSON value in a string, returns NULL in case of error */
-JSON_Value * json_parse_string(const char *string);
-
-/* JSON Object */
-JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
-const char * json_object_get_string (const JSON_Object *object, const char *name);
-JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
-JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
-double json_object_get_number (const JSON_Object *object, const char *name);
-int json_object_get_boolean(const JSON_Object *object, const char *name);
-
-/* dotget functions enable addressing values with dot notation in nested objects,
- just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
- Because valid names in JSON can contain dots, some values may be inaccessible
- this way. */
-JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name);
-const char * json_object_dotget_string (const JSON_Object *object, const char *name);
-JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
-JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
-double json_object_dotget_number (const JSON_Object *object, const char *name);
-int json_object_dotget_boolean(const JSON_Object *object, const char *name);
-
-/* Functions to get available names */
-size_t json_object_get_count(const JSON_Object *object);
-const char * json_object_get_name (const JSON_Object *object, size_t index);
-
-/* JSON Array */
-JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
-const char * json_array_get_string (const JSON_Array *array, size_t index);
-JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
-JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
-double json_array_get_number (const JSON_Array *array, size_t index);
-int json_array_get_boolean(const JSON_Array *array, size_t index);
-size_t json_array_get_count (const JSON_Array *array);
-
-/* JSON Value */
-JSON_Value_Type json_value_get_type (const JSON_Value *value);
-JSON_Object * json_value_get_object (const JSON_Value *value);
-JSON_Array * json_value_get_array (const JSON_Value *value);
-const char * json_value_get_string (const JSON_Value *value);
-double json_value_get_number (const JSON_Value *value);
-int json_value_get_boolean(const JSON_Value *value);
-void json_value_free (JSON_Value *value);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/loragw_pkt_logger/local_conf.json b/loragw_pkt_logger/local_conf.json
deleted file mode 100644
index 624893d..0000000
--- a/loragw_pkt_logger/local_conf.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "gateway_conf": {
- "gateway_ID": "AA555A0000000101"
- }
-}
diff --git a/loragw_pkt_logger/obj/.gitkeep b/loragw_pkt_logger/obj/.gitkeep
deleted file mode 100644
index e69de29..0000000
--- a/loragw_pkt_logger/obj/.gitkeep
+++ /dev/null
diff --git a/loragw_pkt_logger/src/loragw_pkt_logger.c b/loragw_pkt_logger/src/loragw_pkt_logger.c
deleted file mode 100644
index c298878..0000000
--- a/loragw_pkt_logger/src/loragw_pkt_logger.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- / _____) _ | |
-( (____ _____ ____ _| |_ _____ ____| |__
- \____ \| ___ | (_ _) ___ |/ ___) _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
- ©2013 Semtech-Cycleo
-
-Description:
- Configure Lora concentrator and record received packets in a log file
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-Maintainer: Sylvain Miermont
-*/
-
-
-/* -------------------------------------------------------------------------- */
-/* --- DEPENDANCIES --------------------------------------------------------- */
-
-/* fix an issue between POSIX and C99 */
-#if __STDC_VERSION__ >= 199901L
- #define _XOPEN_SOURCE 600
-#else
- #define _XOPEN_SOURCE 500
-#endif
-
-#include <stdint.h> /* C99 types */
-#include <stdbool.h> /* bool type */
-#include <stdio.h> /* printf fprintf sprintf fopen fputs */
-
-#include <string.h> /* memset */
-#include <signal.h> /* sigaction */
-#include <time.h> /* time clock_gettime strftime gmtime clock_nanosleep*/
-#include <unistd.h> /* getopt access */
-#include <stdlib.h> /* atoi */
-
-#include "parson.h"
-#include "loragw_hal.h"
-
-/* -------------------------------------------------------------------------- */
-/* --- PRIVATE MACROS ------------------------------------------------------- */
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#define MSG(args...) fprintf(stderr,"loragw_pkt_logger: " args) /* message that is destined to the user */
-
-/* -------------------------------------------------------------------------- */
-/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */
-
-/* signal handling variables */
-struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
-static int exit_sig = 0; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
-static int quit_sig = 0; /* 1 -> application terminates without shutting down the hardware */
-
-/* configuration variables needed by the application */
-uint64_t lgwm = 0; /* Lora gateway MAC address */
-char lgwm_str[17];
-
-/* clock and log file management */
-time_t now_time;
-time_t log_start_time;
-FILE * log_file = NULL;
-char log_file_name[64];
-
-/* -------------------------------------------------------------------------- */
-/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
-
-static void sig_handler(int sigio);
-
-int parse_SX1301_configuration(const char * conf_file);
-
-int parse_gateway_configuration(const char * conf_file);
-
-void open_log(void);
-
-void usage (void);
-
-/* -------------------------------------------------------------------------- */
-/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
-
-static void sig_handler(int sigio) {
- if (sigio == SIGQUIT) {
- quit_sig = 1;;
- } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
- exit_sig = 1;
- }
-}
-
-int parse_SX1301_configuration(const char * conf_file) {
- int i;
- const char conf_obj[] = "SX1301_conf";
- char param_name[32]; /* used to generate variable parameter names */
- struct lgw_conf_rxrf_s rfconf;
- struct lgw_conf_rxif_s ifconf;
- JSON_Value *root_val;
- JSON_Object *root = NULL;
- JSON_Object *conf = NULL;
- JSON_Value *val;
- uint32_t sf, bw;
-
- /* try to parse JSON */
- root_val = json_parse_file(conf_file);
- root = json_value_get_object(root_val);
- if (root == NULL) {
- MSG("ERROR: %s id not a valid JSON file\n", conf_file);
- exit(EXIT_FAILURE);
- }
- conf = json_object_get_object(root, conf_obj);
- if (conf == NULL) {
- MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj);
- return -1;
- } else {
- MSG("INFO: %s does contain a JSON object named %s, parsing SX1301 parameters\n", conf_file, conf_obj);
- }
-
- /* set configuration for RF chains */
- for (i = 0; i < LGW_RF_CHAIN_NB; ++i) {
- memset(&rfconf, 0, sizeof(rfconf)); /* initialize configuration structure */
- sprintf(param_name, "radio_%i", i); /* compose parameter path inside JSON structure */
- val = json_object_get_value(conf, param_name); /* fetch value (if possible) */
- if (json_value_get_type(val) != JSONObject) {
- MSG("INFO: no configuration for radio %i\n", i);
- continue;
- }
- /* there is an object to configure that radio, let's parse it */
- sprintf(param_name, "radio_%i.enable", i);
- val = json_object_dotget_value(conf, param_name);
- if (json_value_get_type(val) == JSONBoolean) {
- rfconf.enable = (bool)json_value_get_boolean(val);
- } else {
- rfconf.enable = false;
- }
- if (rfconf.enable == false) { /* radio disabled, nothing else to parse */
- MSG("INFO: radio %i disabled\n", i);
- } else { /* radio enabled, will parse the other parameters */
- sprintf(param_name, "radio_%i.freq", i);
- rfconf.freq_hz = (uint32_t)json_object_dotget_number(conf, param_name);
- MSG("INFO: radio %i enabled, center frequency %u\n", i, rfconf.freq_hz);
- }
- /* all parameters parsed, submitting configuration to the HAL */
- if (lgw_rxrf_setconf(i, rfconf) != LGW_HAL_SUCCESS) {
- MSG("WARNING: invalid configuration for radio %i\n", i);
- }
- }
-
- /* set configuration for Lora multi-SF channels (bandwidth cannot be set) */
- for (i = 0; i < LGW_MULTI_NB; ++i) {
- memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */
- sprintf(param_name, "chan_multiSF_%i", i); /* compose parameter path inside JSON structure */
- val = json_object_get_value(conf, param_name); /* fetch value (if possible) */
- if (json_value_get_type(val) != JSONObject) {
- MSG("INFO: no configuration for Lora multi-SF channel %i\n", i);
- continue;
- }
- /* there is an object to configure that Lora multi-SF channel, let's parse it */
- sprintf(param_name, "chan_multiSF_%i.enable", i);
- val = json_object_dotget_value(conf, param_name);
- if (json_value_get_type(val) == JSONBoolean) {
- ifconf.enable = (bool)json_value_get_boolean(val);
- } else {
- ifconf.enable = false;
- }
- if (ifconf.enable == false) { /* Lora multi-SF channel disabled, nothing else to parse */
- MSG("INFO: Lora multi-SF channel %i disabled\n", i);
- } else { /* Lora multi-SF channel enabled, will parse the other parameters */
- sprintf(param_name, "chan_multiSF_%i.radio", i);
- ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, param_name);
- sprintf(param_name, "chan_multiSF_%i.if", i);
- ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, param_name);
- // TODO: handle individual SF enabling and disabling (spread_factor)
- MSG("INFO: Lora multi-SF channel %i enabled, radio %i selected, IF %i Hz, 125 kHz bandwidth, SF 7 to 12\n", i, ifconf.rf_chain, ifconf.freq_hz);
- }
- /* all parameters parsed, submitting configuration to the HAL */
- if (lgw_rxif_setconf(i, ifconf) != LGW_HAL_SUCCESS) {
- MSG("WARNING: invalid configuration for Lora multi-SF channel %i\n", i);
- }
- }
-
- /* set configuration for Lora standard channel */
- memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */
- val = json_object_get_value(conf, "chan_Lora_std"); /* fetch value (if possible) */
- if (json_value_get_type(val) != JSONObject) {
- MSG("INFO: no configuration for Lora standard channel\n");
- } else {
- val = json_object_dotget_value(conf, "chan_Lora_std.enable");
- if (json_value_get_type(val) == JSONBoolean) {
- ifconf.enable = (bool)json_value_get_boolean(val);
- } else {
- ifconf.enable = false;
- }
- if (ifconf.enable == false) {
- MSG("INFO: Lora standard channel %i disabled\n", i);
- } else {
- ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.radio");
- ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, "chan_Lora_std.if");
- bw = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.bandwidth");
- switch(bw) {
- case 500000: ifconf.bandwidth = BW_500KHZ; break;
- case 250000: ifconf.bandwidth = BW_250KHZ; break;
- case 125000: ifconf.bandwidth = BW_125KHZ; break;
- default: ifconf.bandwidth = BW_UNDEFINED;
- }
- sf = (uint32_t)json_object_dotget_number(conf, "chan_Lora_std.spread_factor");
- switch(sf) {
- case 7: ifconf.datarate = DR_LORA_SF7; break;
- case 8: ifconf.datarate = DR_LORA_SF8; break;
- case 9: ifconf.datarate = DR_LORA_SF9; break;
- case 10: ifconf.datarate = DR_LORA_SF10; break;
- case 11: ifconf.datarate = DR_LORA_SF11; break;
- case 12: ifconf.datarate = DR_LORA_SF12; break;
- default: ifconf.datarate = DR_UNDEFINED;
- }
- MSG("INFO: Lora standard channel enabled, radio %i selected, IF %i Hz, %u Hz bandwidth, SF %u\n", ifconf.rf_chain, ifconf.freq_hz, bw, sf);
- }
- if (lgw_rxif_setconf(8, ifconf) != LGW_HAL_SUCCESS) {
- MSG("WARNING: invalid configuration for Lora standard channel\n");
- }
- }
-
- /* set configuration for FSK channel */
- memset(&ifconf, 0, sizeof(ifconf)); /* initialize configuration structure */
- val = json_object_get_value(conf, "chan_FSK"); /* fetch value (if possible) */
- if (json_value_get_type(val) != JSONObject) {
- MSG("INFO: no configuration for FSK channel\n");
- } else {
- val = json_object_dotget_value(conf, "chan_FSK.enable");
- if (json_value_get_type(val) == JSONBoolean) {
- ifconf.enable = (bool)json_value_get_boolean(val);
- } else {
- ifconf.enable = false;
- }
- if (ifconf.enable == false) {
- MSG("INFO: FSK channel %i disabled\n", i);
- } else {
- ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf, "chan_FSK.radio");
- ifconf.freq_hz = (int32_t)json_object_dotget_number(conf, "chan_FSK.if");
- bw = (uint32_t)json_object_dotget_number(conf, "chan_FSK.bandwidth");
- if (bw <= 7800) ifconf.bandwidth = BW_7K8HZ;
- else if (bw <= 15600) ifconf.bandwidth = BW_15K6HZ;
- else if (bw <= 31200) ifconf.bandwidth = BW_31K2HZ;
- else if (bw <= 62500) ifconf.bandwidth = BW_62K5HZ;
- else if (bw <= 125000) ifconf.bandwidth = BW_125KHZ;
- else if (bw <= 250000) ifconf.bandwidth = BW_250KHZ;
- else if (bw <= 500000) ifconf.bandwidth = BW_500KHZ;
- else ifconf.bandwidth = BW_UNDEFINED;
- ifconf.datarate = (uint32_t)json_object_dotget_number(conf, "chan_FSK.datarate");
- MSG("INFO: FSK channel enabled, radio %i selected, IF %i Hz, %u Hz bandwidth, %u bps datarate\n", ifconf.rf_chain, ifconf.freq_hz, bw, ifconf.datarate);
- }
- if (lgw_rxif_setconf(9, ifconf) != LGW_HAL_SUCCESS) {
- MSG("WARNING: invalid configuration for FSK channel\n");
- }
- }
- json_value_free(root_val);
- return 0;
-}
-
-int parse_gateway_configuration(const char * conf_file) {
- const char conf_obj[] = "gateway_conf";
- JSON_Value *root_val;
- JSON_Object *root = NULL;
- JSON_Object *conf = NULL;
- unsigned long long ull = 0;
-
- /* try to parse JSON */
- root_val = json_parse_file(conf_file);
- root = json_value_get_object(root_val);
- if (root == NULL) {
- MSG("ERROR: %s id not a valid JSON file\n", conf_file);
- exit(EXIT_FAILURE);
- }
- conf = json_object_get_object(root, conf_obj);
- if (conf == NULL) {
- MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj);
- return -1;
- } else {
- MSG("INFO: %s does contain a JSON object named %s, parsing gateway parameters\n", conf_file, conf_obj);
- }
-
- /* getting network parameters (only those necessary for the packet logger) */
- sscanf(json_object_dotget_string(conf, "gateway_ID"), "%llx", &ull);
- lgwm = ull;
- MSG("INFO: gateway MAC address is configured to %016llX\n", ull);
-
- json_value_free(root_val);
- return 0;
-}
-
-void open_log(void) {
- int i;
- char iso_date[20];
-
- strftime(iso_date,ARRAY_SIZE(iso_date),"%Y%m%dT%H%M%SZ",gmtime(&now_time)); /* format yyyymmddThhmmssZ */
- log_start_time = now_time; /* keep track of when the log was started, for log rotation */
-
- sprintf(log_file_name, "pktlog_%s_%s.csv", lgwm_str, iso_date);
- log_file = fopen(log_file_name, "a"); /* create log file, append if file already exist */
- if (log_file == NULL) {
- MSG("ERROR: impossible to create log file %s\n", log_file_name);
- exit(EXIT_FAILURE);
- }
-
- i = fprintf(log_file, "\"gateway ID\",\"node MAC\",\"UTC timestamp\",\"us count\",\"frequency\",\"RF chain\",\"RX chain\",\"status\",\"size\",\"modulation\",\"bandwidth\",\"datarate\",\"coderate\",\"RSSI\",\"SNR\",\"payload\"\n");
- if (i < 0) {
- MSG("ERROR: impossible to write to log file %s\n", log_file_name);
- exit(EXIT_FAILURE);
- }
-
- MSG("INFO: Now writing to log file %s\n", log_file_name);
- return;
-}
-
-/* describe command line options */
-void usage(void) {
- MSG( "Available options:\n");
- MSG( " -h print this help\n");
- MSG( " -r <int> rotate log file every N seconds (-1 disable log rotation)\n");
-}
-
-/* -------------------------------------------------------------------------- */
-/* --- MAIN FUNCTION -------------------------------------------------------- */
-
-int main(int argc, char **argv)
-{
- int i, j; /* loop and temporary variables */
- struct timespec sleep_time = {0, 3000000}; /* 3 ms */
-
- /* clock and log rotation management */
- int log_rotate_interval = 3600; /* by default, rotation every hour */
- int time_check = 0; /* variable used to limit the number of calls to time() function */
- unsigned long pkt_in_log = 0; /* count the number of packet written in each log file */
-
- /* configuration file related */
- const char global_conf_fname[] = "global_conf.json"; /* contain global (typ. network-wide) configuration */
- const char local_conf_fname[] = "local_conf.json"; /* contain node specific configuration, overwrite global parameters for parameters that are defined in both */
- const char debug_conf_fname[] = "debug_conf.json"; /* if present, all other configuration files are ignored */
-
- /* allocate memory for packet fetching and processing */
- struct lgw_pkt_rx_s rxpkt[16]; /* array containing up to 16 inbound packets metadata */
- struct lgw_pkt_rx_s *p; /* pointer on a RX packet */
- int nb_pkt;
-
- /* local timestamp variables until we get accurate GPS time */
- struct timespec fetch_time;
- char fetch_timestamp[30];
- struct tm * x;
-
- /* parse command line options */
- while ((i = getopt (argc, argv, "hr:")) != -1) {
- switch (i) {
- case 'h':
- usage();
- return EXIT_FAILURE;
- break;
-
- case 'r':
- log_rotate_interval = atoi(optarg);
- if ((log_rotate_interval == 0) || (log_rotate_interval < -1)) {
- MSG( "ERROR: Invalid argument for -r option\n");
- return EXIT_FAILURE;
- }
- break;
-
- default:
- MSG("ERROR: argument parsing use -h option for help\n");
- usage();
- return EXIT_FAILURE;
- }
- }
-
- /* configure signal handling */
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = 0;
- sigact.sa_handler = sig_handler;
- sigaction(SIGQUIT, &sigact, NULL);
- sigaction(SIGINT, &sigact, NULL);
- sigaction(SIGTERM, &sigact, NULL);
-
- /* configuration files management */
- if (access(debug_conf_fname, R_OK) == 0) {
- /* if there is a debug conf, parse only the debug conf */
- MSG("INFO: found debug configuration file %s, other configuration files will be ignored\n", debug_conf_fname);
- parse_SX1301_configuration(debug_conf_fname);
- parse_gateway_configuration(debug_conf_fname);
- } else if (access(global_conf_fname, R_OK) == 0) {
- /* if there is a global conf, parse it and then try to parse local conf */
- MSG("INFO: found global configuration file %s, trying to parse it\n", global_conf_fname);
- parse_SX1301_configuration(global_conf_fname);
- parse_gateway_configuration(global_conf_fname);
- if (access(local_conf_fname, R_OK) == 0) {
- MSG("INFO: found local configuration file %s, trying to parse it\n", local_conf_fname);
- parse_SX1301_configuration(local_conf_fname);
- parse_gateway_configuration(local_conf_fname);
- }
- } else if (access(local_conf_fname, R_OK) == 0) {
- /* if there is only a local conf, parse it and that's all */
- MSG("INFO: found local configuration file %s, trying to parse it\n", local_conf_fname);
- parse_SX1301_configuration(local_conf_fname);
- parse_gateway_configuration(local_conf_fname);
- } else {
- MSG("ERROR: failed to find any configuration file named %s, %s or %s\n", global_conf_fname, local_conf_fname, debug_conf_fname);
- return EXIT_FAILURE;
- }
-
- /* starting the concentrator */
- i = lgw_start();
- if (i == LGW_HAL_SUCCESS) {
- MSG("INFO: concentrator started, packet can now be received\n");
- } else {
- MSG("ERROR: failed to start the concentrator\n");
- return EXIT_FAILURE;
- }
-
- /* transform the MAC address into a string */
- sprintf(lgwm_str, "%016llX", lgwm);
-
- /* opening log file and writing CSV header*/
- time(&now_time);
- open_log();
-
- /* main loop */
- while ((quit_sig != 1) && (exit_sig != 1)) {
- /* fetch packets */
- nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt);
- if (nb_pkt == LGW_HAL_ERROR) {
- MSG("ERROR: failed packet fetch, exiting\n");
- return EXIT_FAILURE;
- } else if (nb_pkt == 0) {
- clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_time, NULL); /* wait a short time if no packets */
- } else {
- /* local timestamp generation until we get accurate GPS time */
- clock_gettime(CLOCK_REALTIME, &fetch_time);
- x = gmtime(&(fetch_time.tv_sec));
- sprintf(fetch_timestamp,"%04i-%02i-%02i %02i:%02i:%02i.%03liZ",(x->tm_year)+1900,(x->tm_mon)+1,x->tm_mday,x->tm_hour,x->tm_min,x->tm_sec,(fetch_time.tv_nsec)/1000000); /* ISO 8601 format */
- }
-
- /* log packets */
- for (i=0; i < nb_pkt; ++i) {
- p = &rxpkt[i];
-
- /* writing gateway ID */
- fprintf(log_file, "%016llX,", lgwm);
-
- /* writing node MAC address */
- fputs("\"\",", log_file); // TODO: need to parse payload
-
- /* writing UTC timestamp*/
- fprintf(log_file, "\"%s\",", fetch_timestamp);
- // TODO: replace with GPS time when available
-
- /* writing internal clock */
- fprintf(log_file, "%010u,", p->count_us);
-
- /* writing RX frequency */
- fprintf(log_file, "%10u,", p->freq_hz);
-
- /* writing RF chain */
- fprintf(log_file, "%u,", p->rf_chain);
-
- /* writing RX modem/IF chain */
- fprintf(log_file, "%2d,", p->if_chain);
-
- /* writing status */
- switch(p->status) {
- case STAT_CRC_OK: fputs("\"CRC_OK\" ,", log_file); break;
- case STAT_CRC_BAD: fputs("\"CRC_BAD\",", log_file); break;
- case STAT_NO_CRC: fputs("\"NO_CRC\" ,", log_file); break;
- case STAT_UNDEFINED:fputs("\"UNDEF\" ,", log_file); break;
- default: fputs("\"ERR\" ,", log_file);
- }
-
- /* writing payload size */
- fprintf(log_file, "%3u,", p->size);
-
- /* writing modulation */
- switch(p->modulation) {
- case MOD_LORA: fputs("\"LORA\",", log_file); break;
- case MOD_FSK: fputs("\"FSK\" ,", log_file); break;
- default: fputs("\"ERR\" ,", log_file);
- }
-
- /* writing bandwidth */
- switch(p->bandwidth) {
- case BW_500KHZ: fputs("500000,", log_file); break;
- case BW_250KHZ: fputs("250000,", log_file); break;
- case BW_125KHZ: fputs("125000,", log_file); break;
- case BW_62K5HZ: fputs("62500 ,", log_file); break;
- case BW_31K2HZ: fputs("31200 ,", log_file); break;
- case BW_15K6HZ: fputs("15600 ,", log_file); break;
- case BW_7K8HZ: fputs("7800 ,", log_file); break;
- case BW_UNDEFINED: fputs("0 ,", log_file); break;
- default: fputs("-1 ,", log_file);
- }
-
- /* writing datarate */
- if (p->modulation == MOD_LORA) {
- switch (p->datarate) {
- case DR_LORA_SF7: fputs("\"SF7\" ,", log_file); break;
- case DR_LORA_SF8: fputs("\"SF8\" ,", log_file); break;
- case DR_LORA_SF9: fputs("\"SF9\" ,", log_file); break;
- case DR_LORA_SF10: fputs("\"SF10\" ,", log_file); break;
- case DR_LORA_SF11: fputs("\"SF11\" ,", log_file); break;
- case DR_LORA_SF12: fputs("\"SF12\" ,", log_file); break;
- default: fputs("\"ERR\" ,", log_file);
- }
- } else if (p->modulation == MOD_FSK) {
- fprintf(log_file, "\"%6u\",", p->datarate);
- } else {
- fputs("\"ERR\" ,", log_file);
- }
-
- /* writing coderate */
- switch (p->coderate) {
- case CR_LORA_4_5: fputs("\"4/5\",", log_file); break;
- case CR_LORA_4_6: fputs("\"2/3\",", log_file); break;
- case CR_LORA_4_7: fputs("\"4/7\",", log_file); break;
- case CR_LORA_4_8: fputs("\"1/2\",", log_file); break;
- case CR_UNDEFINED: fputs("\"\" ,", log_file); break;
- default: fputs("\"ERR\",", log_file);
- }
-
- /* writing packet RSSI */
- fprintf(log_file, "%+.0f,", p->rssi);
-
- /* writing packet average SNR */
- fprintf(log_file, "%+5.1f,", p->snr);
-
- /* writing hex-encoded payload (bundled in 32-bit words) */
- fputs("\"", log_file);
- for (j = 0; j < p->size; ++j) {
- if ((j > 0) && (j%4 == 0)) fputs("-", log_file);
- fprintf(log_file, "%02X", p->payload[j]);
- }
- fputs("\"\n", log_file);
- ++pkt_in_log;
- }
-
- /* check time and rotate log file if necessary */
- ++time_check;
- if (time_check >= 8) {
- time_check = 0;
- time(&now_time);
- if (difftime(now_time, log_start_time) > log_rotate_interval) {
- fclose(log_file);
- MSG("INFO: log file %s closed, %lu packet(s) recorded\n", log_file_name, pkt_in_log);
- pkt_in_log = 0;
- open_log();
- }
- }
- }
-
- if (exit_sig == 1) {
- /* clean up before leaving */
- i = lgw_stop();
- if (i == LGW_HAL_SUCCESS) {
- MSG("INFO: concentrator stopped successfully\n");
- } else {
- MSG("WARNING: failed to stop concentrator successfully\n");
- }
- fclose(log_file);
- MSG("INFO: log file %s closed, %lu packet(s) recorded\n", log_file_name, pkt_in_log);
- }
-
- MSG("INFO: Exiting packet logger program\n");
- return EXIT_SUCCESS;
-}
-
-/* --- EOF ------------------------------------------------------------------ */
diff --git a/loragw_pkt_logger/src/parson.c b/loragw_pkt_logger/src/parson.c
deleted file mode 100644
index b273ba1..0000000
--- a/loragw_pkt_logger/src/parson.c
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- Parson ( http://kgabis.github.com/parson/ )
- Copyright (c) 2012 Krzysztof Gabis
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
-*/
-
-#include "parson.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#define ERROR 0
-#define SUCCESS 1
-#define STARTING_CAPACITY 15
-#define ARRAY_MAX_CAPACITY 122880 /* 15*(2^13) */
-#define OBJECT_MAX_CAPACITY 960 /* 15*(2^6) */
-#define MAX_NESTING 19
-#define sizeof_token(a) (sizeof(a) - 1)
-#define skip_char(str) ((*str)++)
-#define skip_whitespaces(str) while (isspace(**str)) { skip_char(str); }
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define parson_malloc(a) malloc(a)
-#define parson_free(a) free((void*)a)
-#define parson_realloc(a, b) realloc(a, b)
-
-/* Type definitions */
-typedef union json_value_value {
- const char *string;
- double number;
- JSON_Object *object;
- JSON_Array *array;
- int boolean;
- int null;
-} JSON_Value_Value;
-
-struct json_value_t {
- JSON_Value_Type type;
- JSON_Value_Value value;
-};
-
-struct json_object_t {
- const char **names;
- JSON_Value **values;
- size_t count;
- size_t capacity;
-};
-
-struct json_array_t {
- JSON_Value **items;
- size_t count;
- size_t capacity;
-};
-
-/* Various */
-static int try_realloc(void **ptr, size_t new_size);
-static char * parson_strndup(const char *string, size_t n);
-static int is_utf(const unsigned char *string);
-static int is_decimal(const char *string, size_t length);
-
-/* JSON Object */
-static JSON_Object * json_object_init(void);
-static int json_object_add(JSON_Object *object, const char *name, JSON_Value *value);
-static int json_object_resize(JSON_Object *object, size_t capacity);
-static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n);
-static void json_object_free(JSON_Object *object);
-
-/* JSON Array */
-static JSON_Array * json_array_init(void);
-static int json_array_add(JSON_Array *array, JSON_Value *value);
-static int json_array_resize(JSON_Array *array, size_t capacity);
-static void json_array_free(JSON_Array *array);
-
-/* JSON Value */
-static JSON_Value * json_value_init_object(void);
-static JSON_Value * json_value_init_array(void);
-static JSON_Value * json_value_init_string(const char *string);
-static JSON_Value * json_value_init_number(double number);
-static JSON_Value * json_value_init_boolean(int boolean);
-static JSON_Value * json_value_init_null(void);
-
-/* Parser */
-static void skip_quotes(const char **string);
-static const char * get_processed_string(const char **string);
-static JSON_Value * parse_object_value(const char **string, size_t nesting);
-static JSON_Value * parse_array_value(const char **string, size_t nesting);
-static JSON_Value * parse_string_value(const char **string);
-static JSON_Value * parse_boolean_value(const char **string);
-static JSON_Value * parse_number_value(const char **string);
-static JSON_Value * parse_null_value(const char **string);
-static JSON_Value * parse_value(const char **string, size_t nesting);
-
-/* Various */
-static int try_realloc(void **ptr, size_t new_size) {
- void *reallocated_ptr = parson_realloc(*ptr, new_size);
- if (!reallocated_ptr) { return ERROR; }
- *ptr = reallocated_ptr;
- return SUCCESS;
-}
-
-static char * parson_strndup(const char *string, size_t n) {
- char *output_string = (char*)parson_malloc(n + 1);
- if (!output_string) { return NULL; }
- output_string[n] = '\0';
- strncpy(output_string, string, n);
- return output_string;
-}
-
-static int is_utf(const unsigned char *s) {
- return isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]);
-}
-
-static int is_decimal(const char *string, size_t length) {
- if (length > 1 && string[0] == '0' && string[1] != '.') { return 0; }
- if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') { return 0; }
- while (length--) { if (strchr("xX", string[length])) { return 0; } }
- return 1;
-}
-
-/* JSON Object */
-static JSON_Object * json_object_init(void) {
- JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object));
- if (!new_obj) { return NULL; }
- new_obj->names = (const char**)NULL;
- new_obj->values = (JSON_Value**)NULL;
- new_obj->capacity = 0;
- new_obj->count = 0;
- return new_obj;
-}
-
-static int json_object_add(JSON_Object *object, const char *name, JSON_Value *value) {
- size_t index;
- if (object->count >= object->capacity) {
- size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY);
- if (new_capacity > OBJECT_MAX_CAPACITY) { return ERROR; }
- if (json_object_resize(object, new_capacity) == ERROR) { return ERROR; }
- }
- if (json_object_get_value(object, name) != NULL) { return ERROR; }
- index = object->count;
- object->names[index] = parson_strndup(name, strlen(name));
- if (!object->names[index]) { return ERROR; }
- object->values[index] = value;
- object->count++;
- return SUCCESS;
-}
-
-static int json_object_resize(JSON_Object *object, size_t capacity) {
- if (try_realloc((void**)&object->names, capacity * sizeof(char*)) == ERROR) { return ERROR; }
- if (try_realloc((void**)&object->values, capacity * sizeof(JSON_Value*)) == ERROR) { return ERROR; }
- object->capacity = capacity;
- return SUCCESS;
-}
-
-static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n) {
- size_t i, name_length;
- for (i = 0; i < json_object_get_count(object); i++) {
- name_length = strlen(object->names[i]);
- if (name_length != n) { continue; }
- if (strncmp(object->names[i], name, n) == 0) { return object->values[i]; }
- }
- return NULL;
-}
-
-static void json_object_free(JSON_Object *object) {
- while(object->count--) {
- parson_free(object->names[object->count]);
- json_value_free(object->values[object->count]);
- }
- parson_free(object->names);
- parson_free(object->values);
- parson_free(object);
-}
-
-/* JSON Array */
-static JSON_Array * json_array_init(void) {
- JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array));
- if (!new_array) { return NULL; }
- new_array->items = (JSON_Value**)NULL;
- new_array->capacity = 0;
- new_array->count = 0;
- return new_array;
-}
-
-static int json_array_add(JSON_Array *array, JSON_Value *value) {
- if (array->count >= array->capacity) {
- size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY);
- if (new_capacity > ARRAY_MAX_CAPACITY) { return ERROR; }
- if (!json_array_resize(array, new_capacity)) { return ERROR; }
- }
- array->items[array->count] = value;
- array->count++;
- return SUCCESS;
-}
-
-static int json_array_resize(JSON_Array *array, size_t capacity) {
- if (try_realloc((void**)&array->items, capacity * sizeof(JSON_Value*)) == ERROR) { return ERROR; }
- array->capacity = capacity;
- return SUCCESS;
-}
-
-static void json_array_free(JSON_Array *array) {
- while (array->count--) { json_value_free(array->items[array->count]); }
- parson_free(array->items);
- parson_free(array);
-}
-
-/* JSON Value */
-static JSON_Value * json_value_init_object(void) {
- JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
- if (!new_value) { return NULL; }
- new_value->type = JSONObject;
- new_value->value.object = json_object_init();
- if (!new_value->value.object) { parson_free(new_value); return NULL; }
- return new_value;
-}
-
-static JSON_Value * json_value_init_array(void) {
- JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
- if (!new_value) { return NULL; }
- new_value->type = JSONArray;
- new_value->value.array = json_array_init();
- if (!new_value->value.array) { parson_free(new_value); return NULL; }
- return new_value;
-}
-
-static JSON_Value * json_value_init_string(const char *string) {
- JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
- if (!new_value) { return NULL; }
- new_value->type = JSONString;
- new_value->value.string = string;
- return new_value;
-}
-
-static JSON_Value * json_value_init_number(double number) {
- JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
- if (!new_value) { return NULL; }
- new_value->type = JSONNumber;
- new_value->value.number = number;
- return new_value;
-}
-
-static JSON_Value * json_value_init_boolean(int boolean) {
- JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
- if (!new_value) { return NULL; }
- new_value->type = JSONBoolean;
- new_value->value.boolean = boolean;
- return new_value;
-}
-
-static JSON_Value * json_value_init_null(void) {
- JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
- if (!new_value) { return NULL; }
- new_value->type = JSONNull;
- return new_value;
-}
-
-/* Parser */
-static void skip_quotes(const char **string) {
- skip_char(string);
- while (**string != '\"') {
- if (**string == '\0') { return; }
- if (**string == '\\') { skip_char(string); if (**string == '\0') { return; }}
- skip_char(string);
- }
- skip_char(string);
-}
-
-/* Returns contents of a string inside double quotes and parses escaped
- characters inside.
- Example: "\u006Corem ipsum" -> lorem ipsum */
-static const char * get_processed_string(const char **string) {
- const char *string_start = *string;
- char *output, *processed_ptr, *unprocessed_ptr, current_char;
- unsigned int utf_val;
- skip_quotes(string);
- if (**string == '\0') { return NULL; }
- output = parson_strndup(string_start + 1, *string - string_start - 2);
- if (!output) { return NULL; }
- processed_ptr = unprocessed_ptr = output;
- while (*unprocessed_ptr) {
- current_char = *unprocessed_ptr;
- if (current_char == '\\') {
- unprocessed_ptr++;
- current_char = *unprocessed_ptr;
- switch (current_char) {
- case '\"': case '\\': case '/': break;
- case 'b': current_char = '\b'; break;
- case 'f': current_char = '\f'; break;
- case 'n': current_char = '\n'; break;
- case 'r': current_char = '\r'; break;
- case 't': current_char = '\t'; break;
- case 'u':
- unprocessed_ptr++;
- if (!is_utf((const unsigned char*)unprocessed_ptr) ||
- sscanf(unprocessed_ptr, "%4x", &utf_val) == EOF) {
- parson_free(output); return NULL;
- }
- if (utf_val < 0x80) {
- current_char = utf_val;
- } else if (utf_val < 0x800) {
- *processed_ptr++ = (utf_val >> 6) | 0xC0;
- current_char = ((utf_val | 0x80) & 0xBF);
- } else {
- *processed_ptr++ = (utf_val >> 12) | 0xE0;
- *processed_ptr++ = (((utf_val >> 6) | 0x80) & 0xBF);
- current_char = ((utf_val | 0x80) & 0xBF);
- }
- unprocessed_ptr += 3;
- break;
- default:
- parson_free(output);
- return NULL;
- break;
- }
- } else if ((unsigned char)current_char < 0x20) { /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */
- parson_free(output);
- return NULL;
- }
- *processed_ptr = current_char;
- processed_ptr++;
- unprocessed_ptr++;
- }
- *processed_ptr = '\0';
- if (try_realloc((void**)&output, strlen(output) + 1) == ERROR) { return NULL; }
- return output;
-}
-
-static JSON_Value * parse_value(const char **string, size_t nesting) {
- if (nesting > MAX_NESTING) { return NULL; }
- skip_whitespaces(string);
- switch (**string) {
- case '{':
- return parse_object_value(string, nesting + 1);
- case '[':
- return parse_array_value(string, nesting + 1);
- case '\"':
- return parse_string_value(string);
- case 'f': case 't':
- return parse_boolean_value(string);
- case '-':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- return parse_number_value(string);
- case 'n':
- return parse_null_value(string);
- default:
- return NULL;
- }
-}
-
-static JSON_Value * parse_object_value(const char **string, size_t nesting) {
- JSON_Value *output_value = json_value_init_object(), *new_value = NULL;
- JSON_Object *output_object = json_value_get_object(output_value);
- const char *new_key = NULL;
- if (!output_value) { return NULL; }
- skip_char(string);
- skip_whitespaces(string);
- if (**string == '}') { skip_char(string); return output_value; } /* empty object */
- while (**string != '\0') {
- new_key = get_processed_string(string);
- skip_whitespaces(string);
- if (!new_key || **string != ':') {
- json_value_free(output_value);
- return NULL;
- }
- skip_char(string);
- new_value = parse_value(string, nesting);
- if (!new_value) {
- parson_free(new_key);
- json_value_free(output_value);
- return NULL;
- }
- if(!json_object_add(output_object, new_key, new_value)) {
- parson_free(new_key);
- parson_free(new_value);
- json_value_free(output_value);
- return NULL;
- }
- parson_free(new_key);
- skip_whitespaces(string);
- if (**string != ',') { break; }
- skip_char(string);
- skip_whitespaces(string);
- }
- skip_whitespaces(string);
- if (**string != '}' || /* Trim object after parsing is over */
- json_object_resize(output_object, json_object_get_count(output_object)) == ERROR) {
- json_value_free(output_value);
- return NULL;
- }
- skip_char(string);
- return output_value;
-}
-
-static JSON_Value * parse_array_value(const char **string, size_t nesting) {
- JSON_Value *output_value = json_value_init_array(), *new_array_value = NULL;
- JSON_Array *output_array = json_value_get_array(output_value);
- if (!output_value) { return NULL; }
- skip_char(string);
- skip_whitespaces(string);
- if (**string == ']') { /* empty array */
- skip_char(string);
- return output_value;
- }
- while (**string != '\0') {
- new_array_value = parse_value(string, nesting);
- if (!new_array_value) {
- json_value_free(output_value);
- return NULL;
- }
- if(json_array_add(output_array, new_array_value) == ERROR) {
- parson_free(new_array_value);
- json_value_free(output_value);
- return NULL;
- }
- skip_whitespaces(string);
- if (**string != ',') { break; }
- skip_char(string);
- skip_whitespaces(string);
- }
- skip_whitespaces(string);
- if (**string != ']' || /* Trim array after parsing is over */
- json_array_resize(output_array, json_array_get_count(output_array)) == ERROR) {
- json_value_free(output_value);
- return NULL;
- }
- skip_char(string);
- return output_value;
-}
-
-static JSON_Value * parse_string_value(const char **string) {
- const char *new_string = get_processed_string(string);
- if (!new_string) { return NULL; }
- return json_value_init_string(new_string);
-}
-
-static JSON_Value * parse_boolean_value(const char **string) {
- size_t true_token_size = sizeof_token("true");
- size_t false_token_size = sizeof_token("false");
- if (strncmp("true", *string, true_token_size) == 0) {
- *string += true_token_size;
- return json_value_init_boolean(1);
- } else if (strncmp("false", *string, false_token_size) == 0) {
- *string += false_token_size;
- return json_value_init_boolean(0);
- }
- return NULL;
-}
-
-static JSON_Value * parse_number_value(const char **string) {
- char *end;
- double number = strtod(*string, &end);
- JSON_Value *output_value;
- if (is_decimal(*string, end - *string)) {
- *string = end;
- output_value = json_value_init_number(number);
- } else {
- output_value = NULL;
- }
- return output_value;
-}
-
-static JSON_Value * parse_null_value(const char **string) {
- size_t token_size = sizeof_token("null");
- if (strncmp("null", *string, token_size) == 0) {
- *string += token_size;
- return json_value_init_null();
- }
- return NULL;
-}
-
-/* Parser API */
-JSON_Value * json_parse_file(const char *filename) {
- FILE *fp = fopen(filename, "r");
- size_t file_size;
- char *file_contents;
- JSON_Value *output_value;
- if (!fp) { return NULL; }
- fseek(fp, 0L, SEEK_END);
- file_size = ftell(fp);
- rewind(fp);
- file_contents = (char*)parson_malloc(sizeof(char) * (file_size + 1));
- if (!file_contents) { fclose(fp); return NULL; }
- if (fread(file_contents, file_size, 1, fp) < 1) {
- if (ferror(fp)) { fclose(fp); return NULL; }
- }
- fclose(fp);
- file_contents[file_size] = '\0';
- output_value = json_parse_string(file_contents);
- parson_free(file_contents);
- return output_value;
-}
-
-JSON_Value * json_parse_string(const char *string) {
- if (!string || (*string != '{' && *string != '[')) { return NULL; }
- return parse_value((const char**)&string, 0);
-}
-
-/* JSON Object API */
-JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) {
- return json_object_nget_value(object, name, strlen(name));
-}
-
-const char * json_object_get_string(const JSON_Object *object, const char *name) {
- return json_value_get_string(json_object_get_value(object, name));
-}
-
-double json_object_get_number(const JSON_Object *object, const char *name) {
- return json_value_get_number(json_object_get_value(object, name));
-}
-
-JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) {
- return json_value_get_object(json_object_get_value(object, name));
-}
-
-JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) {
- return json_value_get_array(json_object_get_value(object, name));
-}
-
-int json_object_get_boolean(const JSON_Object *object, const char *name) {
- return json_value_get_boolean(json_object_get_value(object, name));
-}
-
-JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) {
- const char *dot_position = strchr(name, '.');
- if (!dot_position) { return json_object_get_value(object, name); }
- object = json_value_get_object(json_object_nget_value(object, name, dot_position - name));
- return json_object_dotget_value(object, dot_position + 1);
-}
-
-const char * json_object_dotget_string(const JSON_Object *object, const char *name) {
- return json_value_get_string(json_object_dotget_value(object, name));
-}
-
-double json_object_dotget_number(const JSON_Object *object, const char *name) {
- return json_value_get_number(json_object_dotget_value(object, name));
-}
-
-JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) {
- return json_value_get_object(json_object_dotget_value(object, name));
-}
-
-JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) {
- return json_value_get_array(json_object_dotget_value(object, name));
-}
-
-int json_object_dotget_boolean(const JSON_Object *object, const char *name) {
- return json_value_get_boolean(json_object_dotget_value(object, name));
-}
-
-size_t json_object_get_count(const JSON_Object *object) {
- return object ? object->count : 0;
-}
-
-const char * json_object_get_name(const JSON_Object *object, size_t index) {
- if (index >= json_object_get_count(object)) { return NULL; }
- return object->names[index];
-}
-
-/* JSON Array API */
-JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) {
- if (index >= json_array_get_count(array)) { return NULL; }
- return array->items[index];
-}
-
-const char * json_array_get_string(const JSON_Array *array, size_t index) {
- return json_value_get_string(json_array_get_value(array, index));
-}
-
-double json_array_get_number(const JSON_Array *array, size_t index) {
- return json_value_get_number(json_array_get_value(array, index));
-}
-
-JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) {
- return json_value_get_object(json_array_get_value(array, index));
-}
-
-JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) {
- return json_value_get_array(json_array_get_value(array, index));
-}
-
-int json_array_get_boolean(const JSON_Array *array, size_t index) {
- return json_value_get_boolean(json_array_get_value(array, index));
-}
-
-size_t json_array_get_count(const JSON_Array *array) {
- return array ? array->count : 0;
-}
-
-/* JSON Value API */
-JSON_Value_Type json_value_get_type(const JSON_Value *value) {
- return value ? value->type : JSONError;
-}
-
-JSON_Object * json_value_get_object(const JSON_Value *value) {
- return json_value_get_type(value) == JSONObject ? value->value.object : NULL;
-}
-
-JSON_Array * json_value_get_array(const JSON_Value *value) {
- return json_value_get_type(value) == JSONArray ? value->value.array : NULL;
-}
-
-const char * json_value_get_string(const JSON_Value *value) {
- return json_value_get_type(value) == JSONString ? value->value.string : NULL;
-}
-
-double json_value_get_number(const JSON_Value *value) {
- return json_value_get_type(value) == JSONNumber ? value->value.number : 0;
-}
-
-int json_value_get_boolean(const JSON_Value *value) {
- return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1;
-}
-
-void json_value_free(JSON_Value *value) {
- switch (json_value_get_type(value)) {
- case JSONObject:
- json_object_free(value->value.object);
- break;
- case JSONString:
- if (value->value.string) { parson_free(value->value.string); }
- break;
- case JSONArray:
- json_array_free(value->value.array);
- break;
- default:
- break;
- }
- parson_free(value);
-}