From 578fe1b582638b8040e591bd58f9be215bc11e86 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Fri, 24 Nov 2023 00:12:47 +0000 Subject: [PATCH 01/15] Add basic design --- README.md | 4 +++- docs/images/schematic.jpg | Bin 0 -> 14270 bytes 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 docs/images/schematic.jpg diff --git a/README.md b/README.md index cf93ae1b3c..ac76b0d971 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,11 @@ I have placed design thoughts within the ./doc directory within this repository. ## Initial Prototype -The initial prototype can be seen in the image below. +The initial prototype can be seen in the images below. ![Prototype](./docs/images/prototype.jpg) +![Prototype](./docs/images/schematic.jpg) + # Project status diff --git a/docs/images/schematic.jpg b/docs/images/schematic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ea2b21101685e109119ea3ec36f402dee59e30bb GIT binary patch literal 14270 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 literal 0 HcmV?d00001 From 6aa99dea1161aebbe8894f8a26006175f1a0c4b2 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Fri, 24 Nov 2023 17:04:57 +0000 Subject: [PATCH 02/15] GitHub cicd (#3) * CICD test * make scripts executable * Correct Docker Image * Prevent Lunch Menu * Add output.zip * Correct file paths * See where the files are * Stop guesing * Stop guesing2 * test dir * Figure out Monkeybuisiness * Do ls after build.sh * ls in the wrong place * ls in the wrong place * Cleanup * Fix update.img path * Update README.md --------- Co-authored-by: Alistair Jordan --- .BoardConfig.mk | 1 + .github/workflows/build.yaml | 46 ++++++++++++++++++++++++++++++++++++ .gitignore | 1 - README.md | 1 + cicd/docker_brun.sh | 5 ++++ cicd/prepare_runner.sh | 25 ++++++++++++++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) create mode 120000 .BoardConfig.mk create mode 100644 .github/workflows/build.yaml create mode 100755 cicd/docker_brun.sh create mode 100755 cicd/prepare_runner.sh diff --git a/.BoardConfig.mk b/.BoardConfig.mk new file mode 120000 index 0000000000..47eab108de --- /dev/null +++ b/.BoardConfig.mk @@ -0,0 +1 @@ +project/cfg/BoardConfig_IPC/BoardConfig-SPI_NAND-NONE-RV1103_Luckfox_Pico_Mini_B-IPC.mk \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000000..f234059070 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,46 @@ +name: Build +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Prepare build environment + run: ./cicd/prepare_runner.sh + - name: Build + run: ./cicd/docker_brun.sh + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: Balloon${{ github.run_id }}${{ github.run_attempt }} + release_name: Release ${{ github.sha }} + body: | + Contents of this release: + * update.img - Update image for LuckyFox pico Board. + * output.zip - Contents of output folder + draft: true + prerelease: false + - name: Upload Release Asset update.img + id: upload-release-asset-update + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./output/image/update.img + asset_name: update.img + asset_content_type: application/img + - name: Upload Release Asset output.zip + id: upload-release-asset-output + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./output.zip + asset_name: output.zip + asset_content_type: application/zip + \ No newline at end of file diff --git a/.gitignore b/.gitignore index cd93fca863..de0088d297 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # *.o -.BoardConfig.mk RK-RELEASE-NOTES-V1.4.1.txt IMAGE/ output/ diff --git a/README.md b/README.md index 516a4e72d4..cb8d82c0b8 100644 --- a/README.md +++ b/README.md @@ -79,5 +79,6 @@ The initial prototype can be seen in the images below. * It boots into linux and doesn't blow up. * DTS Updated for correct pin attribution * GPS Works +* CI/CD Works * Lora works, LoraWan not * Basically the entire code base is missing. \ No newline at end of file diff --git a/cicd/docker_brun.sh b/cicd/docker_brun.sh new file mode 100755 index 0000000000..d84cfbc2f3 --- /dev/null +++ b/cicd/docker_brun.sh @@ -0,0 +1,5 @@ +set -e + +sudo docker run --privileged --mount type=bind,source="$(pwd)",target=/balloon luckfoxtech/luckfox_pico:1.0 /bin/bash /balloon/build.sh + +zip output.zip output \ No newline at end of file diff --git a/cicd/prepare_runner.sh b/cicd/prepare_runner.sh new file mode 100755 index 0000000000..b65b7ba346 --- /dev/null +++ b/cicd/prepare_runner.sh @@ -0,0 +1,25 @@ +set -e + +# Install binfmt-support and zip +sudo apt install -y binfmt-support qemu-user-static zip + +# Install docker +# Add Docker's official GPG key: +sudo apt-get update +sudo apt-get install ca-certificates curl gnupg +sudo install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg +sudo chmod a+r /etc/apt/keyrings/docker.gpg + +# Add the repository to Apt sources: +echo \ + "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null +sudo apt-get update + +sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + +# Do submodule checkout +git submodule init +git submodule update --depth=1 \ No newline at end of file From 8a9bc89072e304f1cea346c2700f2ecb837fe05a Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Sat, 25 Nov 2023 15:57:35 +0000 Subject: [PATCH 03/15] Gpsd (#4) * Add gpsd * Add gpsd --------- Co-authored-by: Alistair Jordan --- README.md | 2 +- sysdrv/tools/board/buildroot/luckfox_pico_defconfig | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cb8d82c0b8..7c6a2e1127 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The initial prototype can be seen in the images below. * It boots into linux and doesn't blow up. * DTS Updated for correct pin attribution -* GPS Works +* GPS Works, gpsd installed. * CI/CD Works * Lora works, LoraWan not * Basically the entire code base is missing. \ No newline at end of file diff --git a/sysdrv/tools/board/buildroot/luckfox_pico_defconfig b/sysdrv/tools/board/buildroot/luckfox_pico_defconfig index d0cb9a7f64..48eb174b8e 100755 --- a/sysdrv/tools/board/buildroot/luckfox_pico_defconfig +++ b/sysdrv/tools/board/buildroot/luckfox_pico_defconfig @@ -35,3 +35,7 @@ BR2_PACKAGE_SAMBA4=y BR2_PACKAGE_TIME=y BR2_PACKAGE_HTOP=y BR2_PACKAGE_NANO=y +BR2_PACKAGE_GPSD=y +BR2_PACKAGE_GPSD_DEVICES="/dev/ttyS2" +BR2_PACKAGE_GPSD_UBX=y +BR2_PACKAGE_GPSD_PYTHON=y From 2f0e6b6c12a5b6238ab99e7332a68467fe78c141 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Sat, 25 Nov 2023 22:50:07 +0000 Subject: [PATCH 04/15] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c6a2e1127..7669dffef0 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ This design decision has been made for the following reasons: Generally modern GPS modules are simply UART based, use similar chipsets and have essentially all become unified since they became integrated into smartphones. I didn't take much bother into researching this one. They should in theory neary all just be hotswappable. +*Update*: No, no they are not. Added gpsd as a common interface. + #### Camera Module This one needs research. I just picked the smallest, lightest camera I had on hand (It came from a ESP32 kit). Might not be the best solution power wise. This section might need an update. @@ -81,4 +83,4 @@ The initial prototype can be seen in the images below. * GPS Works, gpsd installed. * CI/CD Works * Lora works, LoraWan not -* Basically the entire code base is missing. \ No newline at end of file +* Basically the entire code base is missing. From ca4601182b016f90ea6d8edfd35c12ac0f0cf427 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Sat, 25 Nov 2023 22:54:06 +0000 Subject: [PATCH 05/15] Add "Schematic" drawio diagram. --- docs/images/schematic.xml | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/images/schematic.xml diff --git a/docs/images/schematic.xml b/docs/images/schematic.xml new file mode 100644 index 0000000000..eae26a19a2 --- /dev/null +++ b/docs/images/schematic.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0c4b2d56b7b8543d43e87b391d0cb2ecc062bb81 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Sat, 25 Nov 2023 23:49:35 +0000 Subject: [PATCH 06/15] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7669dffef0..37dc244c6f 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,8 @@ Generally modern GPS modules are simply UART based, use similar chipsets and hav This one needs research. I just picked the smallest, lightest camera I had on hand (It came from a ESP32 kit). Might not be the best solution power wise. This section might need an update. +*Update, who uses a 20 Pin non-conformant MIPI/CSI interface on a dev board?!? Luckfox.. Otherwise the best dev board i've ever worked with :/ + ## Notes on design documentation and Source code The linux module used as the central processor is based on the LuckyFox Pico Mini B. Hence the basis of this git repository is a fork of their SDK for ease of updating any bug fixes for the board. Where there have been significant code changes, the README.md from LuckyFox have been renamed with a _luckyfox.md appendage. From 780459477137afa86111e2d96b015527c903502f Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Sat, 25 Nov 2023 23:50:00 +0000 Subject: [PATCH 07/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37dc244c6f..5c5c549470 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Generally modern GPS modules are simply UART based, use similar chipsets and hav This one needs research. I just picked the smallest, lightest camera I had on hand (It came from a ESP32 kit). Might not be the best solution power wise. This section might need an update. -*Update, who uses a 20 Pin non-conformant MIPI/CSI interface on a dev board?!? Luckfox.. Otherwise the best dev board i've ever worked with :/ +*Update*, who uses a 20 Pin non-conformant MIPI/CSI interface on a dev board?!? Luckfox.. Otherwise the best dev board i've ever worked with :/ ## Notes on design documentation and Source code From 746d84568d12528c7125d0c0166353c10c885d79 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 27 Nov 2023 18:07:36 +0000 Subject: [PATCH 08/15] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5c5c549470..603cbcdd27 100644 --- a/README.md +++ b/README.md @@ -85,4 +85,5 @@ The initial prototype can be seen in the images below. * GPS Works, gpsd installed. * CI/CD Works * Lora works, LoraWan not +* I2C working with Si5351 WSPR, WSPR not * Basically the entire code base is missing. From 5b2e45bf4b509fe1d2d45aa606573f44f302b45e Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 4 Dec 2023 17:04:05 +0000 Subject: [PATCH 09/15] Wspr (#5) * Initial Commit * Si5351 driver working * Base WSPR solution * WSPR works * Cleanup * Re-enable SPI --------- Co-authored-by: Alistair Jordan --- docs/WSPR.md | 29 +++ local.sh | 5 +- sysdrv/cfg/package.mk | 4 + .../boot/dts/rv1103g-luckfox-pico-mini-b.dts | 82 +++++++- .../configs/luckfox_rv1106_linux_defconfig | 1 + sysdrv/tools/board/Makefile.tools.board.mk | 10 +- sysdrv/tools/board/wspr/Makefile | 26 +++ sysdrv/tools/board/wspr/README.md | 6 + sysdrv/tools/board/wspr/debug.h | 32 +++ sysdrv/tools/board/wspr/main.c | 164 +++++++++++++++ sysdrv/tools/board/wspr/wspr.c | 192 ++++++++++++++++++ sysdrv/tools/board/wspr/wspr.h | 46 +++++ 12 files changed, 594 insertions(+), 3 deletions(-) create mode 100644 docs/WSPR.md create mode 100644 sysdrv/tools/board/wspr/Makefile create mode 100644 sysdrv/tools/board/wspr/README.md create mode 100644 sysdrv/tools/board/wspr/debug.h create mode 100644 sysdrv/tools/board/wspr/main.c create mode 100644 sysdrv/tools/board/wspr/wspr.c create mode 100644 sysdrv/tools/board/wspr/wspr.h diff --git a/docs/WSPR.md b/docs/WSPR.md new file mode 100644 index 0000000000..4ee782eccf --- /dev/null +++ b/docs/WSPR.md @@ -0,0 +1,29 @@ +# WSPR Design + +## Introduction + +WSPR is a stands for Weak Signal Propogation Reporter, more information can be found at [https://www.sigidwiki.com/wiki/WSPR]https://www.sigidwiki.com/wiki/WSPR + +WSPR is designed to be able to report incredibly weak signals, and has various base points for detection around the world. This allows communication at an extremely slow speed for location data to provide telemetry. This can be seen on WSPRNet. + +[http://www.wsprnet.org/drupal/WSPRnet/map]WSPRNet + +For use the protocol requires an amateur radio license. For this project, I have aquired one for use of WSPRNet, however anyone using this project will need to aquire a license for themselves in order to use this technology. + +## Base Design + +### Code + +The project is based on [https://github.com/alexf91/WSPR-Beacon/]alexf91/WSPR-Beacon however has been completely rewritten. + +The initial code was designed for an Arduino based solution with a USB interface. The re-write here disregards the code apart from the WSPR encoding library. + +A special mention here is [https://github.com/threeme3/WsprryPi]threeme3/WsprryPi. I's not used in this project, but was vastly helpful for design purposes. + +### Electronics + +The WSPR part of the project requires an oscillator to function at around 14MHz. + +For this it was chosen to use the si5351, for the good community support, and the ease of the i2c interface. + +Technically, it a low pass filter should be added, but given the harmonics of a square wave and the transmission power, for this indiviual use case, I would consider unnecessary. \ No newline at end of file diff --git a/local.sh b/local.sh index ff0a2a76ac..d67f3915c3 100755 --- a/local.sh +++ b/local.sh @@ -3,4 +3,7 @@ if ./build.sh ; then sudo cp -rf output/image ~/nfs/image else echo "Build failure, not copying" -fi \ No newline at end of file +fi + +# Note to self, compiling a single thing is a lot easier when you add the toolchain! +# export PATH=/home/aj/lorawan-balloon/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin:$PATH \ No newline at end of file diff --git a/sysdrv/cfg/package.mk b/sysdrv/cfg/package.mk index 7b39036270..c0fbd86cd4 100644 --- a/sysdrv/cfg/package.mk +++ b/sysdrv/cfg/package.mk @@ -41,3 +41,7 @@ $(eval $(call MACRO_CHECK_ENABLE_PKG, RK_ENABLE_OTA)) # Enable build strace CONFIG_SYSDRV_ENABLE_STRACE=n $(eval $(call MACRO_CHECK_ENABLE_PKG, RK_ENABLE_STRACE)) + +# Enable build WSPR +CONFIG_SYSDRV_ENABLE_WSPR=y +$(eval $(call MACRO_CHECK_ENABLE_PKG, RK_ENABLE_WSPR)) diff --git a/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico-mini-b.dts b/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico-mini-b.dts index e8ea642fd7..fbc2eebfae 100755 --- a/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico-mini-b.dts +++ b/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico-mini-b.dts @@ -20,6 +20,15 @@ regulator-name = "gpio1_pd0"; regulator-always-on; }; + + clocks { + /* 25MHz reference crystal */ + ref25: ref25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + }; }; &sfc { @@ -67,14 +76,85 @@ // status = "disabled"; //}; + // /**********I2C**********/ &i2c3 { status = "okay"; pinctrl-0 = <&i2c3m1_xfer>; clock-frequency = <100000>; +/* Si5351a msop10 i2c clock generator */ + si5351a: clock-generator@60 { + compatible = "silabs,si5351a-msop"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + + /* connect xtal input to 25MHz reference */ + clocks = <&ref25>; + clock-names = "xtal"; + + /* connect xtal input as source of pll0 and pll1 */ + silabs,pll-source = <0 0>, <1 0>; + + /* + * overwrite clkout0 configuration with: + * - 8mA output drive strength + * - pll0 as clock source of multisynth0 + * - multisynth0 as clock source of output divider + * - multisynth0 can change pll0 + * - set initial clock frequency of 74.25MHz + */ + clkout0 { + reg = <0>; + silabs,drive-strength = <8>; + silabs,multisynth-source = <0>; + silabs,clock-source = <0>; + silabs,pll-master; + /* clock-frequency = <74250000>;*/ + }; + + /* + * overwrite clkout1 configuration with: + * - 4mA output drive strength + * - pll1 as clock source of multisynth1 + * - multisynth1 as clock source of output divider + * - multisynth1 can change pll1 + */ + clkout1 { + reg = <1>; + silabs,drive-strength = <4>; + silabs,multisynth-source = <1>; + silabs,clock-source = <0>; + pll-master; + }; + + /* + * overwrite clkout2 configuration with: + * - xtal as clock source of output divider + */ + clkout2 { + reg = <2>; + silabs,clock-source = <2>; + }; + }; + +}; + +&pinctrl { + i2c3 { + /omit-if-no-ref/ + i2c3m1_xfer: i2c3m1-xfer { + rockchip,pins = + /* i2c3_scl_m1 */ + <1 RK_PD3 3 &pcfg_pull_up>, + /* i2c3_sda_m1 */ + <1 RK_PD2 3 &pcfg_pull_up>; + }; + }; }; -// /**********SPI**********/ +/**********SPI**********/ &spi0 { status = "okay"; pinctrl-names = "default"; diff --git a/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig b/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig index 4c54b69658..d1652b1ee2 100755 --- a/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig +++ b/sysdrv/source/kernel/arch/arm/configs/luckfox_rv1106_linux_defconfig @@ -320,3 +320,4 @@ CONFIG_DEBUG_FS=y # CONFIG_SCHED_DEBUG is not set # CONFIG_FTRACE is not set # CONFIG_RUNTIME_TESTING_MENU is not set +CONFIG_COMMON_CLK_SI5351=y diff --git a/sysdrv/tools/board/Makefile.tools.board.mk b/sysdrv/tools/board/Makefile.tools.board.mk index a4bf0eab27..0c8a2fc5ff 100644 --- a/sysdrv/tools/board/Makefile.tools.board.mk +++ b/sysdrv/tools/board/Makefile.tools.board.mk @@ -9,7 +9,8 @@ tools_board-builds: \ board-build-rockchip_test \ board-build-e2fsprogs \ board-build-sysstat \ - board-build-mtd_utils + board-build-mtd_utils \ + board-build-wspr @echo "build tools board done" tools_board-clean: @@ -23,6 +24,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/wspr distclean board-build-toolkits: $(MAKE) -C $(SYSDRV_DIR)/tools/board/toolkits @@ -74,7 +76,13 @@ ifeq ($(BOOT_MEDIUM),spi_nor) popd; endif endif + board-build-sysstat: ifeq ($(ENABLE_SYSSTAT),y) $(MAKE) -C $(SYSDRV_DIR)/tools/board/sysstat endif + +board-build-wspr: +ifeq ($(ENABLE_WSPR),y) + $(MAKE) -C $(SYSDRV_DIR)/tools/board/wspr +endif diff --git a/sysdrv/tools/board/wspr/Makefile b/sysdrv/tools/board/wspr/Makefile new file mode 100644 index 0000000000..225a406de3 --- /dev/null +++ b/sysdrv/tools/board/wspr/Makefile @@ -0,0 +1,26 @@ + +#ifeq ($(SYSDRV_PARAM), ) + WSPR_PARAM:=../../../Makefile.param + include $(WSPR_PARAM) +#endif + +export LC_ALL=C +SHELL:=/bin/bash + +CURRENT_DIR := $(shell pwd) +PKG_NAME := wspr +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 wspr.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) + diff --git a/sysdrv/tools/board/wspr/README.md b/sysdrv/tools/board/wspr/README.md new file mode 100644 index 0000000000..73aa05fef3 --- /dev/null +++ b/sysdrv/tools/board/wspr/README.md @@ -0,0 +1,6 @@ +# WSPR Transmission Code + +This code is designed to transmit WSPR tones and is a largely rewritten version of: +https://github.com/alexf91/WSPR-Beacon/ + +The code directly interfaces with the clock sources through the unix filesystem. \ No newline at end of file diff --git a/sysdrv/tools/board/wspr/debug.h b/sysdrv/tools/board/wspr/debug.h new file mode 100644 index 0000000000..098e8fc8d8 --- /dev/null +++ b/sysdrv/tools/board/wspr/debug.h @@ -0,0 +1,32 @@ +/* + * Copyright 2018 Alexander Fasching + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DEBUG_H +#define DEBUG_H + +#include +#include + +static inline void debug(const char *format, ...) { +#ifdef DEBUG + va_list args; + va_start(args, format); + vprintf(format, args); +#endif +} + +#endif /* DEBUG_H */ diff --git a/sysdrv/tools/board/wspr/main.c b/sysdrv/tools/board/wspr/main.c new file mode 100644 index 0000000000..8530259123 --- /dev/null +++ b/sysdrv/tools/board/wspr/main.c @@ -0,0 +1,164 @@ +/* + * Copyright 2023 Alistair Jordan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include + #include + #include + #include + #include + #include + #include "wspr.h" + #include + #include + #include // for clock_gettime() + + #define BASE_FREQ_LOW 14097000 + // high is end of 200hz spectrum - 6 hz to take account for transmission. + // Useful docs here: https://www.qrp-labs.com/images/ultimate3s/operation3.11.pdf + #define BASE_FREQ_HIGH 14097194 + +/** + * @brief Convert GPS coordinates into the 6 character grid locator. + * @param grid Buffer for the result + * @param lon Longitude in 15.16 signed fixed point format. + * @param lat Latitude in 15.16 signed fixed point format. + * @returns 0 on uccess. + */ +static int8_t gps_to_grid(char *grid, int32_t lon, int32_t lat) { + const int32_t SCALE = 65536; + + int32_t tmp_lon = lon + 180 * SCALE; + int32_t tmp_lat = lat + 90 * SCALE; + + if (tmp_lon < 0 || tmp_lon > 360 * SCALE) + return 1; + if (tmp_lat < 0 || tmp_lat > 180 * SCALE) + return 2; + + /* Convert the longitude */ + grid[0] = tmp_lon / (20 * SCALE) + 'A'; + tmp_lon %= (20 * SCALE); + + grid[2] = tmp_lon / (2 * SCALE) + '0'; + tmp_lon %= (2 * SCALE); + + grid[4] = tmp_lon * 12 / SCALE + 'a'; + + /* Convert the latitude */ + grid[1] = tmp_lat / (10 * SCALE) + 'A'; + tmp_lat %= (10 * SCALE); + + grid[3] = tmp_lat / SCALE + '0'; + tmp_lat %= SCALE; + + grid[5] = tmp_lat * 24 / SCALE + 'a'; + + return 0; +} + +int init_wspr(char *clk) { + char echo_command[100]; + // use system calls for the time being, direct file access seems to be throwing all kinds of errors, and I can't workout why.. + // this needs FIXING! + snprintf(echo_command, sizeof(echo_command), "echo 'enable clk0' > /proc/clk/enable"); + return (system(echo_command)); +} + +int send_tone(uint32_t base_freq, char *data, int index, char *clk) { + char echo_command[100]; + // set freq + // echo [clk_name] [rate(Hz)] > /proc/clk/rate + uint8_t tone = wspr_get_tone(data, index); + uint32_t f = base_freq + (3 * tone) / 2; + printf("Sending tone %i of %i at %i Hz\n",index+1,WSPR_SYMBOL_COUNT,f); + snprintf(echo_command, sizeof(echo_command), "echo 'clk0 %d' > /proc/clk/rate", tone); + return (system(echo_command)); +} + +int stop_wspr(char *clk) { + //disable clk0 + // echo disable [clk_name] > /proc/clk/enable + char echo_command[100]; + // use system calls for the time being, direct file access seems to be throwing all kinds of errors, and I can't workout why.. + // this needs FIXING! + snprintf(echo_command, sizeof(echo_command), "echo 'disable clk0' > /proc/clk/enable"); + return (system(echo_command)); +} + + int main(int argc, char *argv[]) { + char grid[6]; + char callsign[6];//"=2X0UAJ"; + char clk_name[5] = "clk0\0"; + int32_t lon = 0; + int32_t lat = 0; + uint8_t wspr_data[WSPR_BUFFER_SIZE]; + + if (argc < 4) { + printf("Usage is ./wspr lon[int32] lat[int32] CALLSIGN[char[6]]"); + return 1; + } + sscanf(argv[1],"%ld",&lon); + sscanf(argv[2],"%ld",&lat); + sscanf(argv[3],"%s.6",&callsign); + + if (gps_to_grid(grid, lon, lat) != 0) { + printf("Cannot translate long/lat\n"); + return 1; + } + if (wspr_encode(wspr_data, callsign, grid, 7) != 0) { + printf("Cannot encode WSPR message\n"); + return 1; + } + + printf("Decide random frequency within band for transmission\n"); + // Decide base frequency for transmission + srand(time(NULL)); + uint32_t base_freq = BASE_FREQ_LOW + (rand() % (BASE_FREQ_HIGH - BASE_FREQ_LOW)); + printf("Freqeuency decided at %i\n",base_freq); + + printf("Attempt to init %s for transmission\n", clk_name); + // Start transmit + if (init_wspr(clk_name) != 0) { + printf("%s unable to init!\n", clk_name); + return 1; + } + printf("%s init completete, start sending tones.\n", clk_name); + + int msec = 0; + struct timeval start, end; + long secs_used,micros_used; + //printf("Start time: %d\n", start_time); + for (int i=0; i < WSPR_SYMBOL_COUNT; i++) { + gettimeofday(&start, NULL); + if (send_tone(base_freq, wspr_data, i, clk_name) != 0) { + printf("Transmit failure\n"); + break; + } + gettimeofday(&end, NULL); + // account for how long it took for send_tone to work with drift correction + secs_used=(end.tv_sec - start.tv_sec); //avoid overflow by subtracting first + micros_used= ((secs_used*1000000) + end.tv_usec) - (start.tv_usec); + usleep((WSPR_SYMBOL_TIME*1000 - micros_used)); + } + + if (stop_wspr(clk_name) != 0) { + printf("Disconnect device immediately!\n"); + return 2; + } + + printf("Transmission Complete\n"); + +} \ No newline at end of file diff --git a/sysdrv/tools/board/wspr/wspr.c b/sysdrv/tools/board/wspr/wspr.c new file mode 100644 index 0000000000..fc9c675513 --- /dev/null +++ b/sysdrv/tools/board/wspr/wspr.c @@ -0,0 +1,192 @@ +/* + * Copyright 2018 Alexander Fasching + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "debug.h" + + +const uint8_t sync_vector[] = { + 0x03, 0x71, 0xa4, 0x07, 0xa4, 0x40, 0xb3, 0x58, 0x58, 0x95, 0x34, 0x56, + 0x04, 0xc9, 0xcd, 0xe2, 0xa0, 0x0c, 0x58, 0x63, 0x00 +}; + + +/** + * Calculate the parity bits from the value of the shift register. + * The parity bits are returned in bit0 and bit1 of the returned value. + */ +static uint8_t get_parity(uint32_t * shiftreg0, uint32_t * shiftreg1) { + // use Galois-type shift register calculation + // for this to work, polynomials have to be bit-reversed + const uint32_t rev_poly0 = 0x8ACA0B4E; // invert lowest bit because it + const uint32_t rev_poly1 = 0xE23C8626; // is set by having Data put there + + uint8_t par0; + uint8_t par1; + + // if new data bit is 1, apply polynomial to SR + // new data bit is the same in both SRs, so we only need to test LSB once + if(*shiftreg0 & 1){ + *shiftreg0 ^= rev_poly0; + *shiftreg1 ^= rev_poly1; + } + // parity is at MSB + par0 = *shiftreg0 & 0x80000000 ? 1 : 0; + // implement shift in constant + par1 = *shiftreg1 & 0x80000000 ? 2 : 0; + return par1 | par0; +} + + +static void set_bit(uint8_t *bitvector, int index, uint8_t value) { + if (value) + bitvector[index >> 3] |= (1 << (index & 0x07)); + else + bitvector[index >> 3] &= ~(1 << (index & 0x07)); +} + +static uint8_t get_bit(const uint8_t *bitvector, int index) { + return !!(bitvector[index >> 3] & (1 << (index & 0x07))); +} + +static uint8_t bit_reverse(uint8_t byte) { + uint8_t result = 0; + for (int i = 0; i < 8; i++) { + if (byte & (1 << i)) + result |= (1 << (7 - i)); + } + return result; +} + + +//#ifdef DEBUG +static void print_vector(const char *name, const uint8_t *bitvec) { + printf("%s:", name); + for (int i = 0; i < 162; i++) { + if (i % 30 == 0) + printf("\n "); + printf("%d", get_bit(bitvec, i)); + + if (i % 30 != 29) + printf(" "); + } + printf("\n"); +} +//#endif + + +/** + * @brief Encode a WSPR message + * @param call Callsign as string in the format AABCCC + * @param loc 4 character QTH locator as string + * @param power Power in dBm + */ +int wspr_encode(uint8_t *result, const char *call, const char *loc, int power) { + uint32_t call_enc = 0; + + /* Map the callsign to integers between 0 and 36. */ + uint8_t call_mapped[6]; + for (int i = 0; i < 6; i++) { + if ('0' <= call[i] && call[i] <= '9') + call_mapped[i] = call[i] - '0'; + else if ('A' <= call[i] && call[i] <= 'Z') + call_mapped[i] = 10 + call[i] - 'A'; + else if (call[i] == ' ') + call_mapped[i] = 36; + else + return 1; + } + + /* Encode the mapped callsign. */ + call_enc += call_mapped[0]; + call_enc = 36 * call_enc + call_mapped[1]; + call_enc = 10 * call_enc + call_mapped[2]; + call_enc = 27 * call_enc + (call_mapped[3] - 10); + call_enc = 27 * call_enc + (call_mapped[4] - 10); + call_enc = 27 * call_enc + (call_mapped[5] - 10); + + /* Encode the grid locator. */ + uint32_t loc_pwr_enc = (179 - 10 * (loc[0] - 'A') - (loc[2] - '0')) * 180 + + 10 * (loc[1] - 'A') + (loc[3] - '0'); + /* Encode the transmit power. */ + loc_pwr_enc = 128 * loc_pwr_enc + power + 64; + + /* Forward Error Correction */ + uint32_t shiftreg0 = 0; + uint32_t shiftreg1 = 0; + uint8_t packed[21] = {0}; + + for (int i = 0; i < 50; i++) { + uint8_t bit; + if (i < 28) { + uint8_t index = 27 - i; + bit = !!(call_enc & (1UL << index)); + } else { + uint8_t index = 21 - (i - 28); + bit = !!(loc_pwr_enc & (1UL << index)); + } + + shiftreg0 = (shiftreg0 << 1) | bit; + shiftreg1 = (shiftreg1 << 1) | bit; + + uint32_t parity = get_parity(&shiftreg0, &shiftreg1); + uint8_t par0 = !!(parity & (1UL << 0)); + uint8_t par1 = !!(parity & (1UL << 1)); + + set_bit(packed, 2 * i, par0); + set_bit(packed, 2 * i + 1, par1); + } + for (int i = 50; i < 81; i++) { + shiftreg0 <<= 1; + shiftreg1 <<= 1; + + uint32_t parity = get_parity(&shiftreg0, &shiftreg1); + uint8_t par0 = !!(parity & (1 << 0)); + uint8_t par1 = !!(parity & (1 << 1)); + + set_bit(packed, 2 * i, par0); + set_bit(packed, 2 * i + 1, par1); + } + + /* Shuffle the result. */ + memset(result, 0, 21); + uint8_t p = 0; + for (int i = 0; i < 256; i++) { + uint8_t j = bit_reverse(i); + if (j < 162) { + set_bit(result, j, get_bit(packed, p)); + p++; + } + if (p >= 162) + break; + } + +//#ifdef DEBUG + //print_vector("Data symbols", result); + //printf("\n"); + //print_vector("Sync symbols", sync_vector); +//#endif + return 0; +} + + +uint8_t wspr_get_tone(const uint8_t *enc, uint8_t index) { + return get_bit(sync_vector, index) + 2 * get_bit(enc, index); +} diff --git a/sysdrv/tools/board/wspr/wspr.h b/sysdrv/tools/board/wspr/wspr.h new file mode 100644 index 0000000000..d2592ae729 --- /dev/null +++ b/sysdrv/tools/board/wspr/wspr.h @@ -0,0 +1,46 @@ +/* + * Copyright 2018 Alexander Fasching + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WSPR_H +#define WSPR_H + +#define WSPR_BUFFER_SIZE 21 +#define WSPR_SYMBOL_TIME 683 +#define WSPR_SYMBOL_COUNT 162 + + +/** + * @brief Encode a WSPR message + * @param result Buffer of size WSPR_BUFFER_LEN in which the result is stored. + * @param call Callsign as string in the format AABCCC + * @param loc 4 character QTH locator as string + * @param power Power in dBm + */ +int8_t wspr_encode(uint8_t *result, const char *call, const char *loc, int power); + + +/** + * @brief Combine the encoded message with the synchronization vector and + * return the tone that is sent over the air. + * @param enc Encoded message + * @param index Index of the symbol. + * @returns Number of the tone that is sent (0-3) + */ +uint8_t wspr_get_tone(const uint8_t *enc, uint8_t index); + + +#endif /* WSPR_H */ From 8638a52dd280aace638e094c417e7f86a9ab7e67 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 4 Dec 2023 17:05:56 +0000 Subject: [PATCH 10/15] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 603cbcdd27..bb1c33b6ed 100644 --- a/README.md +++ b/README.md @@ -85,5 +85,6 @@ The initial prototype can be seen in the images below. * GPS Works, gpsd installed. * CI/CD Works * Lora works, LoraWan not -* I2C working with Si5351 WSPR, WSPR not +* I2C working with Si5351 +* WSPR Working, Still requires realworld tests * Basically the entire code base is missing. From cfaf88497d0ba86c4f9810abc79ec48b7a94191f Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 4 Dec 2023 17:13:33 +0000 Subject: [PATCH 11/15] Update README.md --- README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bb1c33b6ed..70bbc99f05 100644 --- a/README.md +++ b/README.md @@ -80,11 +80,14 @@ The initial prototype can be seen in the images below. # Project status -* It boots into linux and doesn't blow up. -* DTS Updated for correct pin attribution -* GPS Works, gpsd installed. -* CI/CD Works -* Lora works, LoraWan not -* I2C working with Si5351 -* WSPR Working, Still requires realworld tests -* Basically the entire code base is missing. +* [COMPLETED] It boots into Linux/Buildroot system. +* [COMPLETED] SPI working with Semtec sx1276 FSK Modem. +* [COMPLETED] I2C working with Si5351 Pulse Generator. +* [COMPLETED] UART working with uBlox GPS Module. +* [COMPLETED] GPS Works, gpsd installed. +* [COMPLETED] CI/CD Works. +* [TESTING] WSPR Working, Still requires real-world tests. +* [IN PROGRESS] Lora works, LoraWan not. +* [TODO] "Glue" shell scripts to tack everything together. +* [TODO] CSI Camera Interface with CSI/MIPI camera. +* [TODO] Camera Images to Lorawan Packets From e2e43d0a7495c1054843df8dcbb97c5c50a32c3e Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 4 Dec 2023 17:15:11 +0000 Subject: [PATCH 12/15] Update README.md --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 70bbc99f05..1e8276f0fe 100644 --- a/README.md +++ b/README.md @@ -80,14 +80,14 @@ The initial prototype can be seen in the images below. # Project status -* [COMPLETED] It boots into Linux/Buildroot system. -* [COMPLETED] SPI working with Semtec sx1276 FSK Modem. -* [COMPLETED] I2C working with Si5351 Pulse Generator. -* [COMPLETED] UART working with uBlox GPS Module. -* [COMPLETED] GPS Works, gpsd installed. -* [COMPLETED] CI/CD Works. -* [TESTING] WSPR Working, Still requires real-world tests. -* [IN PROGRESS] Lora works, LoraWan not. -* [TODO] "Glue" shell scripts to tack everything together. -* [TODO] CSI Camera Interface with CSI/MIPI camera. -* [TODO] Camera Images to Lorawan Packets +* [_COMPLETED_] It boots into Linux/Buildroot system. +* [_COMPLETED_] SPI working with Semtec sx1276 FSK Modem. +* [_COMPLETED_] I2C working with Si5351 Pulse Generator. +* [_COMPLETED_] UART working with uBlox GPS Module. +* [_COMPLETED_] GPS Works, gpsd installed. +* [_COMPLETED_] CI/CD Works. +* [_TESTING_] WSPR Working, Still requires real-world tests. +* [_IN PROGRESS_] Lora works, LoraWan not. +* [_TODO_] "Glue" shell scripts to tack everything together. +* [_TODO_] CSI Camera Interface with CSI/MIPI camera. +* [_TODO_] Camera Images to Lorawan Packets From 2b5f5e1203ab3bac3135833f855f4f1d0ba6d822 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 4 Dec 2023 18:16:10 +0000 Subject: [PATCH 13/15] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e8276f0fe..425d6e4745 100644 --- a/README.md +++ b/README.md @@ -90,4 +90,6 @@ The initial prototype can be seen in the images below. * [_IN PROGRESS_] Lora works, LoraWan not. * [_TODO_] "Glue" shell scripts to tack everything together. * [_TODO_] CSI Camera Interface with CSI/MIPI camera. -* [_TODO_] Camera Images to Lorawan Packets +* [_TODO_] Camera Images to Lorawan Packets. +* [_TODO_] LoraWan MAC to IPv4 Bridge. +* From 5d1ecc6ec9a50c9c9bdef88becbb3f767917b781 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 4 Dec 2023 19:22:31 +0000 Subject: [PATCH 14/15] Update README.md --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 425d6e4745..65d6fdb356 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,24 @@ This project is designed to build a linux based LoraWan HAB balloon. The idea of the project is to make an advancement of the current PicoBalloon communities. +## Project Advantages/Disadvantages + +As ever, re-inventing the wheel has it's own pros and cons. This section aims to answer FAQs on why this project has been built and designed. + +### Advantages + +* Linux based - In the past, common sense would have assumed to have used low-power/arduino based microcontrollers. However, as chips have become vastly more efficient and cheaper in recent years (OK, that's a topic for another day!). This means that it has become sensible to start building using Linux. Advantages include being able to use Linux based drivers. For example the LoraWan interface is now a standard linux socket interface, and the HAM radio module can be interfaced with sysfs! +* Ease of development - Linux will allow GDB to be run on the end device for debugging, the environment is running ADB allowing code to easily be pushed or shell to be accessed. Multiple layers of _shit_ can be abstracted... Don't understand the FSK Lora Protocol or SPI interfaces? Fine. It's just a unix socket now! :) +* Ease of build - You can repeat this project with a soldering iron, a few thin wires and a swear jar. +* Sets a new standard of MVP (Minimal Viable Product) - The SDK and simple build means it can be used as a base design for quickly bootstrapping any future projects. + +### Disadvantages + +* Linux based - Yeah, it's not a RTOS. Looking at the drift of WSPR.. eh, famous last words but should be fine. +* Ease of development - It vastly changes the paradigm compared to Arduino based solutions +* Ease of build - WEIGHT!!!!!! - I will work on this one. +* Complexity - While fine once you get used to it... there is a lot going on here. + ## Network design decisions There are 2 major providers of LoraWan coverage: From b5796e7d9c31410ff5b826e9ca890365a5db2608 Mon Sep 17 00:00:00 2001 From: Alistair Jordan Date: Mon, 4 Dec 2023 19:29:47 +0000 Subject: [PATCH 15/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 65d6fdb356..39b482e8df 100644 --- a/README.md +++ b/README.md @@ -110,4 +110,4 @@ The initial prototype can be seen in the images below. * [_TODO_] CSI Camera Interface with CSI/MIPI camera. * [_TODO_] Camera Images to Lorawan Packets. * [_TODO_] LoraWan MAC to IPv4 Bridge. -* +* [_TODO_] Reduce physical weight (Daughter Board?)