lora-packet-forwarder: add package

This adds the `lora_pkt_fwd` which is widely used by all kinds of LoRa
gateways to forward packages to a LoRaWAN broker.

Signed-off-by: Xue Liu <liuxuenetmail@gmail.com>
[rebase, fix commit subject & message]
Signed-off-by: Paul Spooren <mail@aparcar.org>
This commit is contained in:
Xue Liu 2019-03-01 14:34:42 +01:00 committed by Paul Spooren
parent 6f4874ad98
commit 2b7d827ea5
7 changed files with 875 additions and 0 deletions

View File

@ -0,0 +1,64 @@
#
# Copyright (C) 2019 Xue Liu <liuxuenetmail@gmail>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=lora-packet-forwarder
PKG_VERSION:=4.0.1
PKG_RELEASE:=1
PKG_SOURCE_URL:=https://codeload.github.com/Lora-net/packet_forwarder/tar.gz/v$(PKG_VERSION)?
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_HASH:=e68fadf6f1d2e5e7b601e504d5efb48b0a8f374c2c29c0476ab2fe9db68d33ae
PKG_MAINTAINER:=Paul Spooren <mail@aparcar.org>
PKG_LICENSE_FILES:=LICENSE
PKG_BUILD_DIR:=$(BUILD_DIR)/packet_forwarder-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/lora-packet-forwarder
SECTION:=net
CATEGORY:=Network
SUBMENU:=LoRaWAN
TITLE:=Semtech packet-forwarder program
DEPENDS:=+libloragw +libubox-lua +libuci-lua +dkjson
endef
define Package/lora-packet-forwarder/description
A LoRa packet forwarder is a program running on the host of a LoRa gateway
that forwards RF packets receive by the concentrator to a server through a
IP/UDP link, and emits RF packets that are sent by the server.
endef
define Package/lora-packet-forwarder-utils
SECTION:=net
CATEGORY:=Network
SUBMENU:=LoRaWAN
TITLE:=Utilities for lora pakcet forwarder
DEPENDS:=+libloragw
endef
define Package/lora-packet-forwarder/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/lora_pkt_fwd/lora_pkt_fwd $(1)/usr/sbin
$(INSTALL_BIN) ./files/gen_lora_global_conf $(1)/usr/sbin
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/lora_pkt_fwd.init $(1)/etc/init.d/lora_pkt_fwd
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./files/lora-global.config $(1)/etc/config/lora-global
endef
define Package/lora-packet-forwarder-utils/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/util_ack $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/util_sink $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/util_tx_test $(1)/usr/sbin
endef
$(eval $(call BuildPackage,lora-packet-forwarder))
$(eval $(call BuildPackage,lora-packet-forwarder-utils))

View File

@ -0,0 +1,170 @@
-- SPDX-License-Identifier: GPL-2.0
--
-- Copyright (c) 2019 Xue Liu <liuxuenetmail@gmail.com>
--
#!/usr/bin/env lua
require("uloop")
require("ubus")
local json = require("dkjson")
local uci = require("uci")
x = uci.cursor()
uloop.init()
local conn = ubus.connect()
if not conn then
error("Failed to connect to ubus")
end
local lora_global_ubus = conn:call("uci", "get", {config = "lora-global"})
local lora_global_table = lora_global_ubus["values"]
local lora_global = {}
local gateway_conf = {}
local sx1301_conf = {}
local radio_0 = {}
local radio_1 = {}
--
-- chan_x
--
for key, val in pairs(lora_global_table) do
if string.match(key, 'chan_[%a]*', 1) then
local chan = {}
for k, v in pairs(val) do
if string.match(k, '%.[%a]*', 1) == nil then
if tonumber(v) then
chan[k] = tonumber(v)
elseif v == "true" then
chan[k] = true
elseif v == "false" then
chan[k] = false
else
chan[k] = v
end
end
end
sx1301_conf[key] = chan
end
end
--
-- tx_lut_x
--
for key, val in pairs(lora_global_table) do
if string.match(key, 'tx_lut_[%d]?', 1) then
local tx_lut = {}
for k, v in pairs(val) do
if string.match(k, '%.[%a]*', 1) == nil then
if tonumber(v) then
tx_lut[k] = tonumber(v)
elseif v == "true" then
tx_lut[k] = true
elseif v == "false" then
tx_lut[k] = false
else
tx_lut[k] = v
end
end
end
sx1301_conf[key] = tx_lut
end
end
--
-- radio_0
--
if lora_global_table["radio_0"] then
for k, v in pairs(lora_global_table["radio_0"]) do
if string.match(k, '%.[%a]*', 1) == nil then
if tonumber(v) then
radio_0[k] = tonumber(v)
elseif v == "true" then
radio_0[k] = true
elseif v == "false" then
radio_0[k] = false
else
radio_0[k] = v
end
end
end
else
error("UCI configuration has no item radio_0, Please check your configuration")
end
--
-- radio_1
--
if lora_global_table["radio_1"] then
for k, v in pairs(lora_global_table["radio_1"]) do
if string.match(k, '%.[%a]*', 1) == nil then
if tonumber(v) then
radio_1[k] = tonumber(v)
elseif v == "true" then
radio_1[k] = true
elseif v == "false" then
radio_1[k] = false
else
radio_1[k] = v
end
end
end
else
error("UCI configuration has no item radio_1, Please check your configuration")
end
--
-- gateway_conf
--
if lora_global_table["gateway_conf"] then
for k, v in pairs(lora_global_table["gateway_conf"]) do
-- filter out internal uci options
if string.match(k, '%.[%a]*', 1) == nil then
if tonumber(v) then
gateway_conf[k] = tonumber(v)
elseif v == "true" then
gateway_conf[k] = true
elseif v == "false" then
gateway_conf[k] = false
else
gateway_conf[k] = v
end
end
end
else
error("UCI configuration has no item gateway_conf, Please check your configuration")
end
--
-- SX1301_conf
--
if lora_global_table["SX1301_conf"] then
for k, v in pairs(lora_global_table["SX1301_conf"]) do
if string.match(k, '%.[%a]*', 1) == nil then
if tonumber(v) then
sx1301_conf[k] = tonumber(v)
elseif v == "true" then
sx1301_conf[k] = true
elseif v == "false" then
sx1301_conf[k] = false
else
sx1301_conf[k] = v
end
end
end
else
error("UCI configuration has no item SX1301_conf, Please check your configuration")
end
sx1301_conf["radio_0"] = radio_0
sx1301_conf["radio_1"] = radio_1
lora_global["gateway_conf"] = gateway_conf
lora_global["SX1301_conf"] = sx1301_conf
local lora_global_text = json.encode(lora_global, { indent = true })
print(lora_global_text)

View File

@ -0,0 +1,198 @@
config gateway 'gateway_conf'
option keepalive_interval '10'
option stat_interval '30'
option push_timeout_ms '100'
option forward_crc_valid 'true'
option forward_crc_error 'false'
option serv_port_up '1700'
option serv_port_down '1700'
option gateway_ID 'aabbccddeeffaabb'
option server_address 'router.eu.thethings.network'
option forward_crc_disabled 'false'
option gps_enable 'false'
option beacon_enable 'false'
config sx1301 'SX1301_conf'
option clksrc '1'
option antenna_gain '0'
option enable_reset_pin '1'
option reset_pin '25'
option lorawan_public 'true'
config radio 'radio_0'
option enable 'true'
option freq '867500000'
option rssi_offset '-166.0'
option tx_enable 'true'
option tx_freq_min '863000000'
option tx_freq_max '870000000'
option type 'SX1257'
option tx_notch_freq '129000'
config radio 'radio_1'
option enable 'true'
option freq '868500000'
option rssi_offset '-166.0'
option type 'SX1257'
option tx_enable 'false'
config chan 'chan_multiSF_0'
option enable 'true'
option radio '1'
option if '-400000'
option desc 'Lora MAC, 125kHz, all SF, 868.1 MHz'
config chan 'chan_multiSF_1'
option enable 'true'
option radio '1'
option desc 'Lora MAC channel, 125kHz, all SF, 868.3 MHz'
option if '-200000'
config chan 'chan_multiSF_2'
option enable 'true'
option radio '1'
option desc 'Lora MAC channel, 125kHz, all SF, 868.5 MHz'
option if '0'
config chan 'chan_multiSF_3'
option enable 'true'
option radio '0'
option if '-400000'
option desc 'Lora MAC channel, 125kHz, all SF, 867.1 MHz'
config chan 'chan_multiSF_4'
option enable 'true'
option radio '0'
option if '-200000'
option desc 'Lora MAC channel, 125kHz, all SF, 867.3 MHz'
config chan 'chan_multiSF_5'
option enable 'true'
option radio '0'
option if '0'
option desc 'Lora MAC channel, 125kHz, all SF, 867.5 MHz'
config chan 'chan_multiSF_6'
option enable 'true'
option radio '0'
option if '200000'
option desc 'Lora MAC channel, 125kHz, all SF, 867.7 MHz'
config chan 'chan_multiSF_7'
option enable 'true'
option radio '0'
option if '400000'
option desc 'Lora MAC channel, 125kHz, all SF, 867.9 MHz'
config chan 'chan_Lora_std'
option enable 'true'
option radio '1'
option if '-200000'
option desc 'Lora MAC channel, 250kHz, SF7, 868.3 MHz'
option bandwidth '250000'
option spread_factor '7'
config chan 'chan_FSK'
option enable 'true'
option radio '1'
option if '300000'
option desc 'FSK 50kbps channel, 868.8 MHz'
option bandwidth '125000'
option datarate '50000'
config lut 'tx_lut_0'
option pa_gain '0'
option mix_gain '8'
option rf_power '-6'
option dig_gain '0'
config lut 'tx_lut_1'
option pa_gain '0'
option mix_gain '10'
option rf_power '-3'
option dig_gain '0'
config lut 'tx_lut_2'
option pa_gain '0'
option mix_gain '12'
option rf_power '0'
option dig_gain '0'
config lut 'tx_lut_3'
option pa_gain '1'
option mix_gain '8'
option rf_power '3'
option dig_gain '0'
config lut 'tx_lut_4'
option pa_gain '1'
option mix_gain '10'
option rf_power '6'
option dig_gain '0'
config lut 'tx_lut_5'
option pa_gain '1'
option mix_gain '12'
option rf_power '10'
option dig_gain '0'
config lut 'tx_lut_6'
option pa_gain '1'
option mix_gain '13'
option rf_power '11'
option dig_gain '0'
config lut 'tx_lut_7'
option pa_gain '2'
option mix_gain '9'
option rf_power '12'
option dig_gain '0'
config lut 'tx_lut_8'
option pa_gain '1'
option mix_gain '15'
option rf_power '13'
option dig_gain '0'
config lut 'tx_lut_9'
option pa_gain '2'
option mix_gain '10'
option rf_power '14'
option dig_gain '0'
config lut 'tx_lut_10'
option pa_gain '2'
option mix_gain '11'
option rf_power '16'
option dig_gain '0'
config lut 'tx_lut_11'
option pa_gain '3'
option mix_gain '9'
option rf_power '20'
option dig_gain '0'
config lut 'tx_lut_12'
option pa_gain '3'
option mix_gain '10'
option rf_power '23'
option dig_gain '0'
config lut 'tx_lut_13'
option pa_gain '3'
option mix_gain '11'
option rf_power '25'
option dig_gain '0'
config lut 'tx_lut_14'
option pa_gain '3'
option mix_gain '12'
option rf_power '26'
option dig_gain '0'
config lut 'tx_lut_15'
option pa_gain '3'
option mix_gain '14'
option rf_power '27'
option dig_gain '0'

View File

@ -0,0 +1,70 @@
#!/bin/sh /etc/rc.common
START=99
STOP=10
USE_PROCD=1
PROG=/usr/sbin/lora_pkt_fwd
CONFIGFILE=/etc/global_conf.json
reset_sx1301_board ()
{
local pin=$1
logger "lora_pkt_fwd: Reset SX1301 with pin ${pin}"
if [ -d "/sys/class/gpio/gpio${pin}" ]
then
echo 1 > /dev/null
else
echo ${pin} > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio${pin}/direction
fi
echo "1" > /sys/class/gpio/gpio${pin}/value
sleep 5
echo "0" > /sys/class/gpio/gpio${pin}/value
sleep 1
echo "0" > /sys/class/gpio/gpio${pin}/value
logger "lora_pkt_fwd: SX1301 reset completed"
}
generate_global_conf()
{
logger "lora_pkt_fwd: Generate ${CONFIGFILE}"
gen_lora_global_conf > ${CONFIGFILE}
}
start_service()
{
include /lib/functions
logger "lora_pkt_fwd: Start"
config_load lora_pkt_fwd
generate_global_conf
local reset_enable=$(uci get lora-global.SX1301_conf.enable_reset_pin)
if [ ${reset_enable} = 1 ]; then
reset_sx1301_board $(uci get lora-global.SX1301_conf.reset_pin)
fi
procd_open_instance
procd_set_param command $PROG
procd_set_param file ${CONFIGFILE}
procd_set_param file /etc/config/lora-global
procd_set_param respawn
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
stop_service() {
logger "lora_pkt_fwd: Stop"
killall lora_pkt_fwd
}

View File

@ -0,0 +1,15 @@
--- a/lora_pkt_fwd/src/lora_pkt_fwd.c
+++ b/lora_pkt_fwd/src/lora_pkt_fwd.c
@@ -980,9 +980,9 @@ int main(void)
int x;
/* configuration file related */
- char *global_cfg_path= "global_conf.json"; /* contain global (typ. network-wide) configuration */
- char *local_cfg_path = "local_conf.json"; /* contain node specific configuration, overwrite global parameters for parameters that are defined in both */
- char *debug_cfg_path = "debug_conf.json"; /* if present, all other configuration files are ignored */
+ char *global_cfg_path= "/etc/global_conf.json"; /* contain global (typ. network-wide) configuration */
+ char *local_cfg_path = "/etc/local_conf.json"; /* contain node specific configuration, overwrite global parameters for parameters that are defined in both */
+ char *debug_cfg_path = "/etc/debug_conf.json"; /* if present, all other configuration files are ignored */
/* threads */
pthread_t thrid_up;

View File

@ -0,0 +1,50 @@
Index: packet_forwarder-4.0.1/lora_pkt_fwd/src/jitqueue.c
===================================================================
--- packet_forwarder-4.0.1.orig/lora_pkt_fwd/src/jitqueue.c
+++ packet_forwarder-4.0.1/lora_pkt_fwd/src/jitqueue.c
@@ -16,8 +16,7 @@ Maintainer: Michael Coracin
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */
-#define _GNU_SOURCE /* needed for qsort_r to be defined */
-#include <stdlib.h> /* qsort_r */
+#include <stdlib.h>
#include <stdio.h> /* printf, fprintf, snprintf, fopen, fputs */
#include <string.h> /* memset, memcpy */
#include <pthread.h>
@@ -91,32 +90,27 @@ void jit_queue_init(struct jit_queue_s *
pthread_mutex_unlock(&mx_jit_queue);
}
-int compare(const void *a, const void *b, void *arg)
+int compare(const void *a, const void *b)
{
struct jit_node_s *p = (struct jit_node_s *)a;
struct jit_node_s *q = (struct jit_node_s *)b;
- int *counter = (int *)arg;
int p_count, q_count;
p_count = p->pkt.count_us;
q_count = q->pkt.count_us;
- if (p_count > q_count)
- *counter = *counter + 1;
-
return p_count - q_count;
}
void jit_sort_queue(struct jit_queue_s *queue) {
- int counter = 0;
if (queue->num_pkt == 0) {
return;
}
MSG_DEBUG(DEBUG_JIT, "sorting queue in ascending order packet timestamp - queue size:%u\n", queue->num_pkt);
- qsort_r(queue->nodes, queue->num_pkt, sizeof(queue->nodes[0]), compare, &counter);
- MSG_DEBUG(DEBUG_JIT, "sorting queue done - swapped:%d\n", counter);
+ qsort(queue->nodes, queue->num_pkt, sizeof(queue->nodes[0]), compare);
+ MSG_DEBUG(DEBUG_JIT, "sorting queue done - swapped\n");
}
bool jit_collision_test(uint32_t p1_count_us, uint32_t p1_pre_delay, uint32_t p1_post_delay, uint32_t p2_count_us, uint32_t p2_pre_delay, uint32_t p2_post_delay) {

View File

@ -0,0 +1,308 @@
From d4088124704f458f31b3b10768c8f3f50eb9886e Mon Sep 17 00:00:00 2001
From: Xue Liu <liuxuenetmail@gmail.com>
Date: Thu, 21 Feb 2019 15:06:52 +0100
Subject: [PATCH 1/1] - add CMake support
Signed-off-by: Xue Liu <liuxuenetmail@gmail.com>
---
CMakeLists.txt | 72 +++++++++++++++++++++++++++++++++++++
lora_pkt_fwd/CMakeLists.txt | 68 +++++++++++++++++++++++++++++++++++
util_ack/CMakeLists.txt | 36 +++++++++++++++++++
util_sink/CMakeLists.txt | 37 +++++++++++++++++++
util_tx_test/CMakeLists.txt | 43 ++++++++++++++++++++++
5 files changed, 256 insertions(+)
create mode 100644 CMakeLists.txt
create mode 100644 lora_pkt_fwd/CMakeLists.txt
create mode 100644 util_ack/CMakeLists.txt
create mode 100644 util_sink/CMakeLists.txt
create mode 100644 util_tx_test/CMakeLists.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..7e6c18b
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,72 @@
+# -- Minimum required version
+cmake_minimum_required (VERSION 3.2)
+
+# -- Project name
+project (packet_forwarder)
+
+# -- Various includes
+include (CMakePackageConfigHelpers)
+include (GNUInstallDirs)
+include (CheckFunctionExists)
+
+# -- set c99 standard default
+set(CMAKE_C_STANDARD 99)
+
+# -- Required to build
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+find_package(Threads REQUIRED)
+
+# -- Versioning with git tag
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
+ execute_process(
+ COMMAND git describe --tags --always
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ OUTPUT_VARIABLE "packet_forwarder_VERSION"
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(packet_forwarder_VERSION STREQUAL "")
+ set(packet_forwarder_VERSION 0)
+ endif(packet_forwarder_VERSION STREQUAL "")
+ message( STATUS "Git full version: ${packet_forwarder_VERSION}" )
+ execute_process(
+ COMMAND /bin/bash -c "git describe --tags --abbrev=0 | cut --delimiter='v' --fields=2"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ OUTPUT_VARIABLE "packet_forwarder_VERSION_SHORT"
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(packet_forwarder_VERSION_SHORT STREQUAL "")
+ set(packet_forwarder_VERSION_SHORT 0)
+ endif(packet_forwarder_VERSION_SHORT STREQUAL "")
+ message( STATUS "Git version: ${packet_forwarder_VERSION_SHORT}" )
+else(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
+ set(packet_forwarder_VERSION_SHORT 0)
+ set(packet_forwarder_VERSION 0)
+endif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
+
+# -- find packages
+find_package(loragw QUIET)
+if(NOT loragw_FOUND)
+ find_package(PkgConfig)
+ pkg_search_module(LORAGW loragw)
+
+ if(LORAGW_FOUND)
+ message("-- pkg_config: libloragw is found")
+ message("-- libloragw include: ${LORAGW_INCLUDE_DIRS}")
+ message("-- libloragw library: ${LORAGW_LINK_LIBRARIES}")
+ endif()
+else()
+ message("-- CMake: libloragw is found")
+endif()
+
+# -- add the lora_pkt_fwd
+add_subdirectory(lora_pkt_fwd)
+
+# -- add the util_ack
+add_subdirectory(util_ack)
+
+# -- add the util_sink
+add_subdirectory(util_sink)
+
+# -- add the util_tx_test
+add_subdirectory(util_tx_test)
diff --git a/lora_pkt_fwd/CMakeLists.txt b/lora_pkt_fwd/CMakeLists.txt
new file mode 100644
index 0000000..4d61fdd
--- /dev/null
+++ b/lora_pkt_fwd/CMakeLists.txt
@@ -0,0 +1,68 @@
+set(TARGET lora_pkt_fwd)
+
+add_executable(${TARGET} "")
+
+# -- add the compile options
+target_compile_options(
+ ${TARGET}
+ PRIVATE
+ -Wall
+ -Wextra
+)
+
+target_compile_definitions(
+ ${TARGET}
+ PRIVATE
+ VERSION_STRING="${packet_forwarder_VERSION_SHORT}"
+)
+
+target_sources(${TARGET}
+ PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/src/base64.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/jitqueue.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/lora_pkt_fwd.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/parson.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/timersync.c
+)
+
+target_include_directories(${TARGET}
+ PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}
+ ${CMAKE_CURRENT_LIST_DIR}/inc
+)
+
+target_link_libraries(${TARGET}
+ PUBLIC
+ Threads::Threads
+ m
+)
+
+if(LORAGW_FOUND)
+target_include_directories(${TARGET}
+ PRIVATE
+ ${LORAGW_INCLUDE_DIRS}
+)
+
+target_link_libraries(${TARGET}
+ PRIVATE
+ ${LORAGW_LINK_LIBRARIES}
+)
+endif()
+
+if(loragw_FOUND)
+target_link_libraries(${TARGET}
+ PRIVATE
+ Semtech::loragw
+)
+endif()
+
+set_target_properties(${TARGET} PROPERTIES VERSION ${packet_forwarder_VERSION})
+set_target_properties(${TARGET} PROPERTIES SOVERSION ${packet_forwarder_VERSION_SHORT})
+
+# add the install targets
+install (
+ TARGETS ${TARGET}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT shlib
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
diff --git a/util_ack/CMakeLists.txt b/util_ack/CMakeLists.txt
new file mode 100644
index 0000000..b2d776d
--- /dev/null
+++ b/util_ack/CMakeLists.txt
@@ -0,0 +1,36 @@
+
+add_executable(util_ack "")
+target_sources(util_ack
+ PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/src/util_ack.c
+)
+
+if(LORAGW_FOUND)
+target_include_directories(util_ack
+ PRIVATE
+ ${LORAGW_INCLUDE_DIRS}
+)
+
+target_link_libraries(util_ack
+ PRIVATE
+ ${LORAGW_LINK_LIBRARIES}
+)
+endif()
+
+if(loragw_FOUND)
+target_link_libraries(util_ack
+ PRIVATE
+ Semtech::loragw
+)
+endif()
+set_target_properties(util_ack PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+)
+
+# add the install targets
+install (
+ TARGETS util_ack
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT shlib
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
diff --git a/util_sink/CMakeLists.txt b/util_sink/CMakeLists.txt
new file mode 100644
index 0000000..c006fa7
--- /dev/null
+++ b/util_sink/CMakeLists.txt
@@ -0,0 +1,37 @@
+
+add_executable(util_sink "")
+target_sources(util_sink
+ PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/src/util_sink.c
+)
+
+if(LORAGW_FOUND)
+target_include_directories(util_sink
+ PRIVATE
+ ${LORAGW_INCLUDE_DIRS}
+)
+
+target_link_libraries(util_sink
+ PRIVATE
+ ${LORAGW_LINK_LIBRARIES}
+)
+endif()
+
+if(loragw_FOUND)
+target_link_libraries(util_sink
+ PRIVATE
+ Semtech::loragw
+)
+endif()
+
+set_target_properties(util_sink PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+)
+
+# add the install targets
+install (
+ TARGETS util_sink
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT shlib
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
diff --git a/util_tx_test/CMakeLists.txt b/util_tx_test/CMakeLists.txt
new file mode 100644
index 0000000..2207cac
--- /dev/null
+++ b/util_tx_test/CMakeLists.txt
@@ -0,0 +1,43 @@
+
+add_executable(util_tx_test "")
+target_sources(util_tx_test
+ PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/src/util_tx_test.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/base64.c
+)
+
+target_include_directories(util_tx_test
+ PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/inc
+)
+
+if(LORAGW_FOUND)
+target_include_directories(util_tx_test
+ PRIVATE
+ ${LORAGW_INCLUDE_DIRS}
+)
+
+target_link_libraries(util_tx_test
+ PRIVATE
+ ${LORAGW_LINK_LIBRARIES}
+)
+endif()
+
+if(loragw_FOUND)
+target_link_libraries(util_tx_test
+ PRIVATE
+ Semtech::loragw
+)
+endif()
+
+set_target_properties(util_tx_test PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
+)
+
+# add the install targets
+install (
+ TARGETS util_tx_test
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT shlib
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
--
2.20.1