From fa05a389f448e1110fcc9d865747d5cc61bc6224 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 4 Dec 2023 20:10:32 +0000 Subject: [PATCH] Lora wan interface (#6) * Working Lora/LoraWan modules * Start adding testing for LoraWan * Add EU Region * Add EU region, and start lorawan-bridge --------- Co-authored-by: Alistair Jordan --- README.md | 2 +- docs/LoraWanHelium.md | 2 +- sysdrv/cfg/package.mk | 5 + sysdrv/drv_ko/Makefile | 2 +- sysdrv/drv_ko/lorawan/lrwreg.c | 77 ++++++- sysdrv/drv_ko/lorawan/lrwsec.c | 2 +- sysdrv/drv_ko/lorawan/lrwsec.h | 14 ++ sysdrv/drv_ko/lorawan/socket.c | 3 +- sysdrv/tools/board/Makefile.tools.board.mk | 7 + sysdrv/tools/board/lorawan-bridge/Makefile | 25 +++ sysdrv/tools/board/lorawan-bridge/main.c | 224 +++++++++++++++++++++ 11 files changed, 355 insertions(+), 8 deletions(-) create mode 100644 sysdrv/tools/board/lorawan-bridge/Makefile create mode 100644 sysdrv/tools/board/lorawan-bridge/main.c diff --git a/README.md b/README.md index 39b482e8df..4cfcfbacb7 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ The initial prototype can be seen in the images below. * [_COMPLETED_] GPS Works, gpsd installed. * [_COMPLETED_] CI/CD Works. * [_TESTING_] WSPR Working, Still requires real-world tests. -* [_IN PROGRESS_] Lora works, LoraWan not. +* [_IN PROGRESS_] Lora works, LoraWan not tested, added EU region, missing others in kernel driver. * [_TODO_] "Glue" shell scripts to tack everything together. * [_TODO_] CSI Camera Interface with CSI/MIPI camera. * [_TODO_] Camera Images to Lorawan Packets. diff --git a/docs/LoraWanHelium.md b/docs/LoraWanHelium.md index 511b76301f..148f6a7e41 100644 --- a/docs/LoraWanHelium.md +++ b/docs/LoraWanHelium.md @@ -18,5 +18,5 @@ _Overall_ - there are two choices. The former, while a PITA initially, actually provides what initially appears to be an easy to use interface to Lora, with functions such as spreading factor, band etc all controllable using ioctl calls. -The solution here will likely be to create the MAC "Driver" in userland. Should it be there? Absolutely not. (But, once again future improvement, otherwise the project will never get finished.) +It appears that Starnight has also produced a LoraWan driver, which is currently written for the 4.11 kernel, which needs updating to the current kernel and testing. diff --git a/sysdrv/cfg/package.mk b/sysdrv/cfg/package.mk index c0fbd86cd4..10c383bb23 100644 --- a/sysdrv/cfg/package.mk +++ b/sysdrv/cfg/package.mk @@ -42,6 +42,11 @@ $(eval $(call MACRO_CHECK_ENABLE_PKG, RK_ENABLE_OTA)) CONFIG_SYSDRV_ENABLE_STRACE=n $(eval $(call MACRO_CHECK_ENABLE_PKG, RK_ENABLE_STRACE)) + +# Enable build lorawan-bridge +CONFIG_SYSDRV_ENABLE_LORAWAN_BRIDGE=y +$(eval $(call MACRO_CHECK_ENABLE_PKG, RK_ENABLE_LORAWAN_BRIDGE)) + # Enable build WSPR CONFIG_SYSDRV_ENABLE_WSPR=y $(eval $(call MACRO_CHECK_ENABLE_PKG, RK_ENABLE_WSPR)) diff --git a/sysdrv/drv_ko/Makefile b/sysdrv/drv_ko/Makefile index c9effed3b9..3800a9f153 100644 --- a/sysdrv/drv_ko/Makefile +++ b/sysdrv/drv_ko/Makefile @@ -14,7 +14,7 @@ PKG_BIN := out M_OUT_DIR := $(CURRENT_DIR)/$(PKG_BIN) export M_OUT_DIR -M_DIRS := rockit kmpp wifi motor sx1276 +M_DIRS := rockit kmpp wifi motor sx1276 lorawan ################################################################################ ## build target ################################################################################ diff --git a/sysdrv/drv_ko/lorawan/lrwreg.c b/sysdrv/drv_ko/lorawan/lrwreg.c index 855c8f4501..4310430a40 100644 --- a/sysdrv/drv_ko/lorawan/lrwreg.c +++ b/sysdrv/drv_ko/lorawan/lrwreg.c @@ -48,6 +48,64 @@ static struct lrw_dr us902_928_drs[] = { {}, }; +static struct lrw_dr eu863_870_drs[] = { + {.sf = 12, .bw = 125000, .mode = LRW_LORA}, + {.sf = 11, .bw = 125000, .mode = LRW_LORA}, + {.sf = 10, .bw = 125000, .mode = LRW_LORA}, + {.sf = 9, .bw = 125000, .mode = LRW_LORA}, + {.sf = 8, .bw = 125000, .mode = LRW_LORA}, + {.sf = 7, .bw = 125000, .mode = LRW_LORA}, + {.sf = 7, .bw = 250000, .mode = LRW_LORA}, + {}, +}; + +static struct lrw_tx_power eu863_870_txpws[] = { + {.dbm = 16}, + {.dbm = 14}, + {.dbm = 12}, + {.dbm = 10}, + {.dbm = 8}, + {.dbm = 6}, + {.dbm = 4}, + {.dbm = 2} +}; + +static struct lrw_payload_len eu863_870_pl_nofopt[] = { + {.m = 59, .n = 51}, + {.m = 59, .n = 51}, + {.m = 59, .n = 51}, + {.m = 123, .n = 115}, + {.m = 250, .n = 242}, + {.m = 250, .n = 242}, + {.m = 250, .n = 242}, + {}, +}; + +static struct lrw_payload_len eu863_870_pl_fopt[] = { + {.m = 59, .n = 51}, + {.m = 59, .n = 51}, + {.m = 59, .n = 51}, + {.m = 123, .n = 115}, + {.m = 230, .n = 222}, + {.m = 230, .n = 222}, + {.m = 230, .n = 222}, + {}, +}; + +u32 eu863_870_ch2frq(u8 dir, u8 ch) +{ + u32 frq_base; + u32 frq; + u32 step; + + frq_base = 863100000; + step = 200000; + frq = frq_base + step * ch; + + return frq; +} + + static struct lrw_tx_power us902_928_txpws[] = { {.dbm = 30}, {.dbm = 28}, @@ -165,7 +223,20 @@ u32 as923_ch2frq(u8 dir, u8 ch) } static const struct lrw_region_parm reg_parms[] = { - [LRW_EU863_870] = {}, + [LRW_EU863_870] = { + .sync_word = 0x34, + .preamble_len = 8, + .drt = eu863_870_drs, + .pwt = eu863_870_txpws, + .plt[0] = eu863_870_pl_fopt, + .plt[1] = eu863_870_pl_nofopt, + .ch_2_frq = eu863_870_ch2frq, + .rx_delay1 = HZ, + .rx_delay2 = 2 * HZ, + .join_accept_delay1 = 5 * HZ, + .join_accept_delay2 = 6 * HZ, + .ack_timeout = 2 * HZ, + }, [LRW_US902_928] = { .sync_word = 0x34, .preamble_len = 8, @@ -181,9 +252,9 @@ static const struct lrw_region_parm reg_parms[] = { .ack_timeout = 2 * HZ, }, [LRW_CN779_787] = {}, - [LRW_EU443] = {}, +// [LRW_EU443] = {}, [LRW_AU915_928] = {}, - [LRW_CN470_510] = {}, +// [LRW_CN470_510] = {}, [LRW_AS923] = { .sync_word = 0x34, .preamble_len = 8, diff --git a/sysdrv/drv_ko/lorawan/lrwsec.c b/sysdrv/drv_ko/lorawan/lrwsec.c index c99de531d0..1d48a59e7c 100644 --- a/sysdrv/drv_ko/lorawan/lrwsec.c +++ b/sysdrv/drv_ko/lorawan/lrwsec.c @@ -155,7 +155,7 @@ lrw_aes_enc(struct crypto_skcipher *tfm, u8 *in, size_t len, u8 *out) { u8 iv[16]; struct scatterlist src, dst; - SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); + SKCIPHER_REQUEST_ON_STACK(req, tfm); int err; memset(iv, 0, 16); diff --git a/sysdrv/drv_ko/lorawan/lrwsec.h b/sysdrv/drv_ko/lorawan/lrwsec.h index cd8a2d71b0..604f56d9c4 100644 --- a/sysdrv/drv_ko/lorawan/lrwsec.h +++ b/sysdrv/drv_ko/lorawan/lrwsec.h @@ -54,4 +54,18 @@ int lrw_decrypt_buf(struct crypto_skcipher *tfm, u8 dir, u8 *devaddr, u32 fcnt, u8 *buf, size_t len); void lrw_encrypt_key_free(struct crypto_skcipher *tfm); +/* +#define SKCIPHER_REQUEST_ON_STACK(name, tfm) \ + char __##name##_desc[sizeof(struct skcipher_request) + \ + crypto_skcipher_reqsize(tfm)] CRYPTO_MINALIGN_ATTR; \ + struct skcipher_request *name = (void *)__##name##_desc +*/ + +#define SKCIPHER_MAX_REQSIZE 472 + +#define SKCIPHER_REQUEST_ON_STACK(name, tfm) \ +char __##name##_desc[sizeof(struct skcipher_request) + \ + SKCIPHER_MAX_REQSIZE] CRYPTO_MINALIGN_ATTR; \ +struct skcipher_request *name = (void *)__##name##_desc + #endif diff --git a/sysdrv/drv_ko/lorawan/socket.c b/sysdrv/drv_ko/lorawan/socket.c index 38a8e1c059..46ac896189 100644 --- a/sysdrv/drv_ko/lorawan/socket.c +++ b/sysdrv/drv_ko/lorawan/socket.c @@ -1,6 +1,7 @@ #include #include #include +#include #include /* For TIOCOUTQ/INQ */ #include @@ -380,7 +381,7 @@ dgram_getsockopt(struct sock *sk, int level, int optname, static int dgram_setsockopt(struct sock *sk, int level, int optname, - struct sockptr_t *optval, unsigned int optlen) + sockptr_t optval, unsigned int optlen) { int val; int err = 0; diff --git a/sysdrv/tools/board/Makefile.tools.board.mk b/sysdrv/tools/board/Makefile.tools.board.mk index 0c8a2fc5ff..f1af4b9dea 100644 --- a/sysdrv/tools/board/Makefile.tools.board.mk +++ b/sysdrv/tools/board/Makefile.tools.board.mk @@ -10,6 +10,7 @@ tools_board-builds: \ board-build-e2fsprogs \ board-build-sysstat \ board-build-mtd_utils \ + board-build-lorawan-bridge \ board-build-wspr @echo "build tools board done" @@ -24,6 +25,7 @@ tools_board-clean: $(MAKE) -C $(SYSDRV_DIR)/tools/board/stressapptest distclean $(MAKE) -C $(SYSDRV_DIR)/tools/board/rk_ota distclean $(MAKE) -C $(SYSDRV_DIR)/tools/board/sysstat distclean + $(MAKE) -C $(SYSDRV_DIR)/tools/board/lorawan-bridge distclean $(MAKE) -C $(SYSDRV_DIR)/tools/board/wspr distclean board-build-toolkits: @@ -82,6 +84,11 @@ ifeq ($(ENABLE_SYSSTAT),y) $(MAKE) -C $(SYSDRV_DIR)/tools/board/sysstat endif +board-build-lorawan-bridge: +ifeq ($(ENABLE_LORAWAN_BRIDGE),y) + $(MAKE) -C $(SYSDRV_DIR)/tools/board/lorawan-bridge +endif + board-build-wspr: ifeq ($(ENABLE_WSPR),y) $(MAKE) -C $(SYSDRV_DIR)/tools/board/wspr diff --git a/sysdrv/tools/board/lorawan-bridge/Makefile b/sysdrv/tools/board/lorawan-bridge/Makefile new file mode 100644 index 0000000000..2db38913e4 --- /dev/null +++ b/sysdrv/tools/board/lorawan-bridge/Makefile @@ -0,0 +1,25 @@ + +#ifeq ($(SYSDRV_PARAM), ) + LORAWAN_BRIDGE_PARAM:=../../../Makefile.param + include $(LORAWAN_BRIDGE_PARAM) +#endif + +export LC_ALL=C +SHELL:=/bin/bash + +CURRENT_DIR := $(shell pwd) +PKG_NAME := lbr +PKG_BIN := out + +all: + @test -f $(PKG_BIN)/usr/sbin/$(PKG_NAME)_noexist || (\ + mkdir -p $(CURRENT_DIR)/$(PKG_BIN)/usr/sbin; \ + $(SYSDRV_CROSS)-gcc -g main.c -o $(CURRENT_DIR)/$(PKG_BIN)/usr/sbin/$(PKG_NAME); \ + ) + $(call MAROC_COPY_PKG_TO_SYSDRV_OUTPUT, $(SYSDRV_DIR_OUT_ROOTFS), $(PKG_BIN)) +# $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNEL_DIR) M=$(shell pwd) $@ -j12 + +clean: distclean + +distclean: + -rm -rf $(PKG_NAME) $(PKG_BIN) \ No newline at end of file diff --git a/sysdrv/tools/board/lorawan-bridge/main.c b/sysdrv/tools/board/lorawan-bridge/main.c new file mode 100644 index 0000000000..43faf7f772 --- /dev/null +++ b/sysdrv/tools/board/lorawan-bridge/main.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include + +//#include "lora-ioctl.h" + +#define PF_LORAWAN PF_MAX +#define AF_LORAWAN PF_LORAWAN + +enum { + LRW_ADDR_APPEUI, + LRW_ADDR_DEVEUI, + LRW_ADDR_DEVADDR, +}; + +struct lrw_addr_in { + int addr_type; + union { + uint64_t app_eui; + uint64_t dev_eui; + uint32_t devaddr; + }; +}; + +struct sockaddr_lorawan { + sa_family_t family; /* AF_LORAWAN */ + struct lrw_addr_in addr_in; +}; + +/* DEV ioctl() commands */ + +enum LRW_IOC_CMDS { + SIOCGLRWSTATE = SIOCDEVPRIVATE, + SIOCSLRWSTATE, + SIOCGLRWFREQ, + SIOCSLRWFREQ, + SIOCGLRWBW, + SIOCSLRWBW, + SIOCGLRWTXPWR, + SIOCSLRWTXPWR, + SIOCGLRWSPRF, + SIOCSLRWSPRF, + SIOCGLRWLNA, + SIOCSLRWLNA, + SIOCGLRWRSSI, + SIOCGLRWSNR, +}; + +/* Bit 1: 1 for ready to read, 0 for not ready + * Bit 0: 1 for ready to write, 0 for not write + */ +//uint8_t ready2rw(int fd) +//{ +// fd_set read_fds, write_fds; +// struct timeval tv = {.tv_sec = 5, .tv_usec = 0}; +// uint8_t flag; +// +// /* I/O multiplexing. */ +// FD_ZERO(&read_fds); +// FD_ZERO(&write_fds); +// FD_SET(fd, &read_fds); +// FD_SET(fd, &write_fds); +// if (select(fd+1, &read_fds, &write_fds, NULL, &tv) == -1) +// perror("Select failed"); +// +// flag = 0; +// /* Read from the file descriptor if it is ready to be read. */ +// if (FD_ISSET(fd, &read_fds)) { +// flag |= (1 << 1); +// } +// /* Write to the file descriptor if it is ready to be written. */ +// if (FD_ISSET(fd, &write_fds)) { +// flag |= (1 << 0); +// } +// +// return flag; +//} + +//#define ready2read(fd) (ready2rw(fd) & (1 << 1)) +//#define ready2write(fd) (ready2rw(fd) & (1 << 0)) + +int main(int argc, char **argv) +{ + char *data; + char pstr[40]; + int sock; + struct sockaddr_lorawan src_addr, dst_addr; + struct ifreq ifr; + int32_t pwr = 100; +#define MAX_BUFFER_LEN 16 + char buf[MAX_BUFFER_LEN]; + int len; + unsigned int s; + int ret; + + /* Parse command. */ + if (argc >= 2) { + //path = argv[1]; + data = argv[1]; + } + else { + printf("Need more arguments.\r\n"); + return -1; + } + + sock = socket(PF_LORAWAN, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket error\n"); + return -1; + } + + src_addr.family = AF_LORAWAN; + src_addr.addr_in.addr_type = LRW_ADDR_DEVADDR; + src_addr.addr_in.devaddr = 0x01020304; + printf("Going to bind address %X\n", src_addr.addr_in.devaddr); + ret = bind(sock, (struct sockaddr *)&src_addr, sizeof(src_addr)); + if (sock < 0) { + perror("bind error\n"); + return ret; + } + + strcpy(ifr.ifr_name, "lora0"); + ifr.ifr_data = (void *)&pwr; + ret = ioctl(sock, SIOCSLRWTXPWR, &ifr); + if(ioctl(sock, SIOCSLRWTXPWR, &ifr) < 0) { + perror("ioctl error"); + return ret; + } + + dst_addr.family = AF_LORAWAN; + dst_addr.addr_in.addr_type = LRW_ADDR_DEVADDR; + dst_addr.addr_in.devaddr = 0xFFFFFFFF; + len = sendto(sock, data, strlen(data), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr)); + if (len < 0) { + perror("sendto"); + } + +// /* Open device node. */ +// fd = open(path, O_RDWR); +// if (fd == -1) { +// sprintf(pstr, "Open %s failed", path); +// perror(pstr); +// return -1; +// } +// printf("Opened %s\n", path); +// +// set_state(fd, LORA_START); +// /*Set the RF spreading factor. */ +// uint32_t sprf = 2048; +// set_sprfactor(fd, sprf); +// printf("Going to set the RF spreading factor %u chips\n", sprf); +// +// /* Set the RF bandwidth. */ +// uint32_t bw = 125000; +// set_bw(fd, bw); +// printf("Going to set the RF bandwith %u Hz\n", bw); +// +// /* Set the RF power. */ +// int32_t power = 10; +// set_power(fd, power); +// printf("Going to set the RF power %d dbm\n", power); +// +// printf("The current RSSI is %d dbm\n", get_rssi(fd)); +// +// /* Write to the file descriptor if it is ready to be written. */ +// printf("Going to write %s\n", path); +// s = 0; +// while (!ready2write(fd)) { +// sleep(1); +// s++; +// printf("\t%s is not ready to write, do other things.", path); +// printf(" %u s\r", s); +// } +// printf("\n"); +// len = do_write(fd, data, strlen(data)); +// if (len < 0) +// perror("Error"); +// else +// printf("Written %d bytes: %s\n", len, data); +// +// /* Read from echo if it is ready to be read. */ +// memset(buf, 0, MAX_BUFFER_LEN); +// printf("Going to read %s\n", path); +// /* Set the device in read state. */ +// set_state(fd, LORA_STATE_RX); +// s = 0; +// while (!ready2read(fd)) { +// sleep(1); +// s++; +// printf("\t%s is not ready to read, do other things.", path); +// printf(" %u s\r", s); +// } +// printf("\n"); +// len = do_read(fd, buf, MAX_BUFFER_LEN - 1); +// if (len > 0) +// printf("Read %d bytes: %s\n", len, buf); +// +// printf("The LoRa carrier frequency is %u Hz\n", get_freq(fd)); +// printf("The RF spreading factor is %u chips\n", get_sprfactor(fd)); +// printf("The RF bandwith is %u Hz\n", get_bw(fd)); +// printf("The current RSSI is %d dbm\n", get_rssi(fd)); +// printf("The last packet SNR is %d db\n", get_snr(fd)); +// printf("The output power is %d dbm\n", get_power(fd)); +// printf("The LNA gain is %d db\n", get_lna(fd)); +// +// /* Set the device in sleep state. */ +// set_state(fd, LORA_STATE_SLEEP); +// printf("The LoRa device is in 0x%X state\n", get_state(fd)); + + sleep(10); +// set_state(fd, LORA_STOP); + /* Close device node. */ + shutdown(sock, SHUT_RDWR); + close(sock); + + return 0; +} \ No newline at end of file