diff --git a/Makefile b/Makefile index 6b5d00dc..5688ac1c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,14 @@ +all: DEBUG_BEHAVIOR= all: libax5043.a all: radioafsk all: radiocw +all: telem + +debug: DEBUG_BEHAVIOR = -DDEBUG_LOGGING +debug: libax5043.a +debug: radioafsk +debug: radiocw +debug: telem rebuild: clean rebuild: all @@ -22,6 +30,7 @@ clean: rm -f */*/*.o rm -rf ax5043/doc/html rm -rf ax5043/doc/latex + rm -f telem docs: mkdir -p ax5043/doc; cd ax5043; doxygen Doxyfile @@ -44,67 +53,68 @@ libax5043.a: ax5043/spi/ax5043spi.o radiochat: libax5043.a radiochat: chat/chat_main.o - gcc -o radiochat -pthread -L./ chat/chat_main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o radiochat -pthread -L./ chat/chat_main.o -lwiringPi -lax5043 radiocw: libax5043.a radiocw: cw/cw_main.o radiocw: afsk/ax25.o radiocw: afsk/ax5043.o radiocw: afsk/send_afsk.o - gcc -o radiocw -L./ afsk/ax25.o afsk/ax5043.o afsk/send_afsk.o cw/cw_main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o radiocw -L./ afsk/ax25.o afsk/ax5043.o afsk/send_afsk.o cw/cw_main.o -lwiringPi -lax5043 radiopiglatin: libax5043.a radiopiglatin: piglatin/piglatin_main.o - gcc -o radiopiglatin -pedantic -Wall -Wextra -L./ piglatin/piglatin_main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o radiopiglatin -pedantic -Wall -Wextra -L./ piglatin/piglatin_main.o -lwiringPi -lax5043 testax5043tx: libax5043.a testax5043tx: transmit/transmit_main.o - gcc -o testax5043tx -pedantic -Wall -Wextra -L./ transmit/transmit_main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o testax5043tx -pedantic -Wall -Wextra -L./ transmit/transmit_main.o -lwiringPi -lax5043 testax5043rx: libax5043.a testax5043rx: receive/receive_main.o - gcc -o testax5043rx -pedantic -Wall -Wextra -L./ receive/receive_main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o testax5043rx -pedantic -Wall -Wextra -L./ receive/receive_main.o -lwiringPi -lax5043 testax5043init: libax5043.a testax5043init: init/init_main.o - gcc -o testax5043init -pedantic -Wall -Wextra -L./ init/init_main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o testax5043init -pedantic -Wall -Wextra -L./ init/init_main.o -lwiringPi -lax5043 testax50432freq: libax5043.a testax50432freq: transmit2freq/transmit2freq_main.o - gcc -o testax50432freq -pedantic -Wall -Wextra -L./ transmit2freq/transmit2freq_main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o testax50432freq -pedantic -Wall -Wextra -L./ transmit2freq/transmit2freq_main.o -lwiringPi -lax5043 testafsktx: libax5043.a testafsktx: afsktx/ax25.o testafsktx: afsktx/ax5043.o testafsktx: afsktx/main.o - gcc -o testafsktx -pedantic -Wall -Wextra -L./ afsktx/ax25.o afsktx/ax5043.o afsktx/main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o testafsktx -pedantic -Wall -Wextra -L./ afsktx/ax25.o afsktx/ax5043.o afsktx/main.o -lwiringPi -lax5043 radioafsk: libax5043.a radioafsk: afsk/ax25.o radioafsk: afsk/ax5043.o radioafsk: afsk/main.o -radioafsk: afsk/ina219.h - gcc -o radioafsk -pedantic -Wall -Wextra -L./ afsk/ax25.o afsk/ax5043.o afsk/main.o -lwiringPi -lax5043 + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o radioafsk -pedantic -Wall -Wextra -L./ afsk/ax25.o afsk/ax5043.o afsk/main.o -lwiringPi -lax5043 -lm +telem: afsk/telem.o + gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o telem -pedantic -Wall -Wextra -L./ afsk/telem.o -lwiringPi ax5043/generated/configcommon.o: ax5043/generated/configcommon.c ax5043/generated/configcommon.o: ax5043/generated/configrx.h ax5043/generated/configcommon.o: ax5043/generated/configtx.h ax5043/generated/configcommon.o: ax5043/axradio/axradioinit.h ax5043/generated/configcommon.o: ax5043/axradio/axradioinit_p.h - cd ax5043/generated; gcc -pedantic -Wall -Wextra -c configcommon.c + cd ax5043/generated; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c configcommon.c ax5043/generated/configrx.o: ax5043/generated/configrx.c ax5043/generated/configrx.o: ax5043/generated/configrx.h ax5043/generated/configrx.o: ax5043/axradio/axradioinit.h ax5043/generated/configrx.o: ax5043/axradio/axradioinit_p.h - cd ax5043/generated; gcc -pedantic -Wall -Wextra -c configrx.c + cd ax5043/generated; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c configrx.c ax5043/generated/configtx.o: ax5043/generated/configtx.c ax5043/generated/configtx.o: ax5043/generated/configtx.h ax5043/generated/configtx.o: ax5043/axradio/axradioinit.h ax5043/generated/configtx.o: ax5043/axradio/axradioinit_p.h - cd ax5043/generated; gcc -pedantic -Wall -Wextra -c configtx.c + cd ax5043/generated; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c configtx.c ax5043/generated/config.o: ax5043/generated/config.c ax5043/generated/config.o: ax5043/generated/config.h @@ -113,12 +123,12 @@ ax5043/generated/config.o: ax5043/axradio/axradioinit_p.h ax5043/generated/config.o: ax5043/spi/ax5043spi.h ax5043/generated/config.o: ax5043/spi/ax5043spi_p.h ax5043/generated/config.o: ax5043/crc/crc.h - cd ax5043/generated; gcc -pedantic -Wall -Wextra -c config.c + cd ax5043/generated; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c config.c ax5043/spi/ax5043spi.o: ax5043/spi/ax5043spi.c ax5043/spi/ax5043spi.o: ax5043/spi/ax5043spi.h ax5043/spi/ax5043spi.o: ax5043/spi/ax5043spi_p.h - cd ax5043/spi; gcc -pedantic -Wall -Wextra -c ax5043spi.c + cd ax5043/spi; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c ax5043spi.c ax5043/ax5043support/ax5043init.o: ax5043/ax5043support/ax5043init.c ax5043/ax5043support/ax5043init.o: ax5043/ax5043support/ax5043init.h @@ -126,7 +136,7 @@ ax5043/ax5043support/ax5043init.o: ax5043/axradio/axradioinit.h ax5043/ax5043support/ax5043init.o: ax5043/axradio/axradioinit_p.h ax5043/ax5043support/ax5043init.o: ax5043/spi/ax5043spi.h ax5043/ax5043support/ax5043init.o: ax5043/spi/ax5043spi_p.h - cd ax5043/ax5043support; gcc -pedantic -Wall -Wextra -c ax5043init.c + cd ax5043/ax5043support; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c ax5043init.c ax5043/ax5043support/ax5043rx.o: ax5043/ax5043support/ax5043rx.c ax5043/ax5043support/ax5043rx.o: ax5043/ax5043support/ax5043rx.h @@ -134,7 +144,7 @@ ax5043/ax5043support/ax5043rx.o: ax5043/axradio/axradioinit.h ax5043/ax5043support/ax5043rx.o: ax5043/axradio/axradioinit_p.h ax5043/ax5043support/ax5043rx.o: ax5043/spi/ax5043spi.h ax5043/ax5043support/ax5043rx.o: ax5043/spi/ax5043spi_p.h - cd ax5043/ax5043support; gcc -pedantic -Wall -Wextra -c ax5043rx.c + cd ax5043/ax5043support; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c ax5043rx.c ax5043/ax5043support/ax5043tx.o: ax5043/ax5043support/ax5043tx.c ax5043/ax5043support/ax5043tx.o: ax5043/ax5043support/ax5043tx.h @@ -142,7 +152,7 @@ ax5043/ax5043support/ax5043tx.o: ax5043/axradio/axradioinit.h ax5043/ax5043support/ax5043tx.o: ax5043/axradio/axradioinit_p.h ax5043/ax5043support/ax5043tx.o: ax5043/spi/ax5043spi.h ax5043/ax5043support/ax5043tx.o: ax5043/spi/ax5043spi_p.h - cd ax5043/ax5043support; gcc -pedantic -Wall -Wextra -c ax5043tx.c + cd ax5043/ax5043support; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c ax5043tx.c ax5043/axradio/axradioinit.o: ax5043/axradio/axradioinit.c ax5043/axradio/axradioinit.o: ax5043/axradio/axradioinit.h @@ -152,7 +162,7 @@ ax5043/axradio/axradioinit.o: ax5043/spi/ax5043spi.h ax5043/axradio/axradioinit.o: ax5043/spi/ax5043spi_p.h ax5043/axradio/axradioinit.o: ax5043/generated/config.h ax5043/axradio/axradioinit.o: ax5043/crc/crc.h - cd ax5043/axradio; gcc -pedantic -Wall -Wextra -c axradioinit.c + cd ax5043/axradio; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c axradioinit.c ax5043/axradio/axradiomode.o: ax5043/axradio/axradiomode.c ax5043/axradio/axradiomode.o: ax5043/axradio/axradiomode.h @@ -162,7 +172,7 @@ ax5043/axradio/axradiomode.o: ax5043/axradio/axradioinit_p.h ax5043/axradio/axradiomode.o: ax5043/spi/ax5043spi.h ax5043/axradio/axradiomode.o: ax5043/spi/ax5043spi_p.h ax5043/axradio/axradiomode.o: ax5043/generated/config.h - cd ax5043/axradio; gcc -pedantic -Wall -Wextra -c axradiomode.c + cd ax5043/axradio; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c axradiomode.c ax5043/axradio/axradiorx.o: ax5043/axradio/axradiorx.c ax5043/axradio/axradiorx.o: ax5043/axradio/axradiorx.h @@ -172,7 +182,7 @@ ax5043/axradio/axradiorx.o: ax5043/axradio/axradioinit.h ax5043/axradio/axradiorx.o: ax5043/axradio/axradioinit_p.h ax5043/axradio/axradiorx.o: ax5043/spi/ax5043spi.h ax5043/axradio/axradiorx.o: ax5043/spi/ax5043spi_p.h - cd ax5043/axradio; gcc -pedantic -Wall -Wextra -c axradiorx.c + cd ax5043/axradio; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c axradiorx.c ax5043/axradio/axradiotx.o: ax5043/axradio/axradiotx.c ax5043/axradio/axradiotx.o: ax5043/axradio/axradiotx.h @@ -186,11 +196,11 @@ ax5043/axradio/axradiotx.o: ax5043/generated/config.h ax5043/axradio/axradiotx.o: ax5043/axradio/axradiomode.h ax5043/axradio/axradiotx.o: ax5043/axradio/axradiomode_p.h ax5043/axradio/axradiotx.o: ax5043/crc/crc.h - cd ax5043/axradio; gcc -pedantic -Wall -Wextra -c axradiotx.c + cd ax5043/axradio; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c axradiotx.c ax5043/crc/crc.o: ax5043/crc/crc.c ax5043/crc/crc.o: ax5043/crc/crc.h - cd ax5043/crc; gcc -pedantic -Wall -Wextra -c crc.c + cd ax5043/crc; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -pedantic -Wall -Wextra -c crc.c chat/chat_main.o: chat/chat_main.c chat/chat_main.o: ax5043/spi/ax5043spi.h @@ -204,13 +214,13 @@ chat/chat_main.o: ax5043/axradio/axradiorx_p.h chat/chat_main.o: ax5043/axradio/axradiotx.h chat/chat_main.o: ax5043/axradio/axradiotx_p.h chat/chat_main.o: ax5043/generated/configtx.h - cd chat; gcc -I../ax5043 -pedantic -Wconversion -Wall -Wextra -c chat_main.c; cd .. + cd chat; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I../ax5043 -pedantic -Wconversion -Wall -Wextra -c chat_main.c; cd .. afsk/ax25.o: afsk/ax25.c afsk/ax25.o: afsk/ax25.h afsk/ax25.o: afsk/ax5043.h afsk/ax25.o: afsk/status.h - cd afsk; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c ax25.c; cd .. + cd afsk; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c ax25.c; cd .. afsk/ax5043.o: afsk/ax5043.c afsk/ax5043.o: afsk/ax25.h @@ -219,21 +229,26 @@ afsk/ax5043.o: afsk/status.h afsk/ax5043.o: afsk/utils.h afsk/ax5043.o: afsk/main.c afsk/ax5043.o: ax5043/spi/ax5043spi.h - cd afsk; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c ax5043.c; cd .. + cd afsk; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c ax5043.c; cd .. afsk/main.o: afsk/main.c afsk/main.o: afsk/status.h afsk/main.o: afsk/ax5043.h afsk/main.o: afsk/ax25.h afsk/main.o: ax5043/spi/ax5043spi.h - cd afsk; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c main.c; cd .. +afsk/main.o: afsk/Adafruit_INA219.h + cd afsk; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c main.c; cd .. + +afsk/telem.o: afsk/telem.c +afsk/telem.o: afsk/Adafruit_INA219.h + cd afsk; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c telem.c; cd .. afsk/send_afsk.o: afsk/send_afsk.c afsk/send_afsk.o: afsk/send_afsk.h afsk/send_afsk.o: afsk/status.h afsk/send_afsk.o: afsk/ax5043.h afsk/send_afsk.o: afsk/ax25.h - cd afsk; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c send_afsk.c; cd .. + cd afsk; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c send_afsk.c; cd .. cw/cw_main.o: cw/cw_main.c cw/cw_main.o: ax5043/spi/ax5043spi.h @@ -247,7 +262,7 @@ cw/cw_main.o: ax5043/axradio/axradiorx_p.h cw/cw_main.o: ax5043/axradio/axradiotx.h cw/cw_main.o: ax5043/axradio/axradiotx_p.h cw/cw_main.o: ax5043/generated/configtx.h - cd cw; gcc -I../ax5043 -pedantic -Wconversion -Wall -Wextra -c cw_main.c; cd .. + cd cw; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I../ax5043 -pedantic -Wconversion -Wall -Wextra -c cw_main.c; cd .. piglatin/piglatin_main.o: piglatin/piglatin_main.c piglatin/piglatin_main.o: ax5043/spi/ax5043spi.h @@ -261,7 +276,7 @@ piglatin/piglatin_main.o: ax5043/axradio/axradiorx_p.h piglatin/piglatin_main.o: ax5043/axradio/axradiotx.h piglatin/piglatin_main.o: ax5043/axradio/axradiotx_p.h piglatin/piglatin_main.o: ax5043/generated/configtx.h - cd piglatin; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c piglatin_main.c; cd .. + cd piglatin; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c piglatin_main.c; cd .. receive/receive_main.o: receive/receive_main.c receive/receive_main.o: ax5043/axradio/axradioinit.h @@ -273,7 +288,7 @@ receive/receive_main.o: ax5043/axradio/axradiomode_p.h receive/receive_main.o: ax5043/axradio/axradiorx.h receive/receive_main.o: ax5043/axradio/axradiorx_p.h receive/receive_main.o: ax5043/generated/configrx.h - cd receive; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c receive_main.c; cd .. + cd receive; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c receive_main.c; cd .. transmit/transmit_main.o: transmit/transmit_main.c transmit/transmit_main.o: ax5043/axradio/axradioinit.h @@ -285,7 +300,7 @@ transmit/transmit_main.o: ax5043/axradio/axradiomode_p.h transmit/transmit_main.o: ax5043/axradio/axradiotx.h transmit/transmit_main.o: ax5043/axradio/axradiotx_p.h transmit/transmit_main.o: ax5043/generated/configtx.h - cd transmit; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c transmit_main.c; cd .. + cd transmit; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c transmit_main.c; cd .. transmit2freq/transmit2freq_main.o: transmit2freq/transmit2freq_main.c transmit2freq/transmit2freq_main.o: ax5043/axradio/axradioinit.h @@ -297,20 +312,20 @@ transmit2freq/transmit2freq_main.o: ax5043/axradio/axradiomode_p.h transmit2freq/transmit2freq_main.o: ax5043/axradio/axradiotx.h transmit2freq/transmit2freq_main.o: ax5043/axradio/axradiotx_p.h transmit2freq/transmit2freq_main.o: ax5043/generated/configtx.h - cd transmit2freq; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c transmit2freq_main.c; cd .. + cd transmit2freq; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c transmit2freq_main.c; cd .. init/init_main.o: init/init_main.c init/init_main.o: ax5043/axradio/axradioinit.h init/init_main.o: ax5043/axradio/axradioinit_p.h init/init_main.o: ax5043/spi/ax5043spi.h init/init_main.o: ax5043/spi/ax5043spi_p.h - cd init; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c init_main.c; cd .. + cd init; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c init_main.c; cd .. afsktx/ax25.o: afsktx/ax25.c afsktx/ax25.o: afsktx/ax25.h afsktx/ax25.o: afsktx/ax5043.h afsktx/ax25.o: afsktx/status.h - cd afsktx; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c ax25.c; cd .. + cd afsktx; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c ax25.c; cd .. afsktx/ax5043.o: afsktx/ax5043.c afsktx/ax5043.o: afsktx/ax25.h @@ -318,11 +333,11 @@ afsktx/ax5043.o: afsktx/ax5043.h afsktx/ax5043.o: afsktx/status.h afsktx/ax5043.o: afsktx/utils.h afsktx/ax5043.o: ax5043/spi/ax5043spi.h - cd afsktx; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c ax5043.c; cd .. + cd afsktx; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c ax5043.c; cd .. afsktx/main.o: afsktx/main.c afsktx/main.o: afsktx/status.h afsktx/main.o: afsktx/ax5043.h afsktx/main.o: afsktx/ax25.h afsktx/main.o: ax5043/spi/ax5043spi.h - cd afsktx; gcc -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c main.c; cd .. + cd afsktx; gcc -std=gnu99 $(DEBUG_BEHAVIOR) -I ../ax5043 -pedantic -Wconversion -Wall -Wextra -c main.c; cd .. diff --git a/README.md b/README.md index d9367e2f..2ffbc606 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,149 @@ # CubeSatSim -The CubeSat Simulator https://github.com/alanbjohnston/CubeSatSim/wiki is a low cost satellite emulator that run on solar panels and batteries, transmits UHF radio telemetry, has a 3D printed frame, and can be extended by additional sensors and modules. This project is sponsored by the not-for-profit [Radio Amateur Satellite Corporation, AMSAT®](https://amsat.org). +The CubeSat Simulator https://github.com/alanbjohnston/CubeSatSim/wiki is a low cost satellite emulator that runs on solar panels and batteries, transmits UHF radio telemetry, has a 3D printed frame, and can be extended by additional sensors and modules. This project is sponsored by the not-for-profit [Radio Amateur Satellite Corporation, AMSAT®](https://amsat.org). -See the Wiki Software Install page for more details: https://github.com/alanbjohnston/CubeSatSim/wiki/Software-Install. To build and run the software on a Raspberry Pi 3B, 3B+, or Pi Zero W: +There are several hardware versions and software branches to go with them - see below for information. + +See the Wiki Software Install page for more details: https://github.com/alanbjohnston/CubeSatSim/wiki/Software-Install. To build and run the software on a Raspberry Pi 3B, 3B+, or Pi Zero W (doesn't work on Pi 4 since rpitx doesn't work on it yet): +Requires: +- Raspbian Stretch or Buster, full desktop or Lite +- wiringpi +- git +- libasound2-dev +- pi-power-button +- Direwolf +- rpitx + +See the Wiki Software Install page for more details: https://github.com/alanbjohnston/CubeSatSim/wiki/Software-Install. To build and run the software on a Raspberry Pi 3B, 3B+, or Pi Zero W (Does NOT work on a Pi 4 since rpitx does not work on it yet): + +`sudo apt-get install -y wiringpi git libasound2-dev i2c-tools` + +Run raspi-config and enable the I2C bus by selecting Option 5 Interfacing Options and then Option 5 I2C and selecting Y to enable the ARM I2C bus: + +`sudo raspi-config` + +Select Finish at the bottom to exit raspi-config. Then type: + +`sudo cp /boot/config.txt /boot/config.txt.0` + +`sudo nano /boot/config.txt` + +Use the down arrow key to go down in the file until you find this line: + +`# Additional overlays and parameters are documented /boot/overlays/README ` + +Add the following two lines under it: + +`dtoverlay=i2c-gpio` + +`dtoverlay=pi3-miniuart-bt` + +Press Ctrl-X then type `y` then hit Enter to save the file and exit the editor. You should back at the pi@... prompt. + +Edit the cmdline.txt file by typing: + +`sudo cp /boot/cmdline.txt /boot/cmdline.txt.0` + +`sudo nano /boot/cmdline.txt` + +Remove the following text in cmdline.txt to prevent a console from running on the serial port: + +`console=serial0,115200` + +Press Ctrl-X then type `y` then hit Enter to save the file and exit the editor. You should back at the pi@... prompt. + +Reboot by typing: + +`sudo reboot now` + +after logging back into the Pi, type: + +`ls -a /dev/i2c*` + +you should see two I2C buses: + +`i2c-1 i2c-3` + +Continue the install by typing: + +`cd` + +Then type: `git clone http://github.com/alanbjohnston/CubeSatSim.git` `cd CubeSatSim` -Edit the afsk/main.c file to set your amateur radio callsign, then +`git checkout universal` + +Create a sim.cfg configuration file with your amateur radio callsign by typing: + +`echo "callsign" >> sim.cfg` + +Compile the code: `make rebuild` -To hear CW telemetry (Morse code), tune your radio or SDR to 435.297 MHz and enter: +`cd` -`./radiocw` +`git clone https://www.github.com/wb2osz/direwolf` -To stop, Ctrl-C. To hear AFSK telemetry (X.25 data), your radio or SDR to 440.389 MHz FM, and you should receive telemetry from the CubeSat Sim: +`cd direwolf` -`./radioafsk` +`make -j` -This code uses the Brandenburg Tech Digital Transceiver, based on DigitalTxRxRP https://brandenburgtech.wordpress.com/ +(takes a while) -This repository contains: - - - afsk - Code that sends telemetry in 1k2 AFSK X.25 format - - arduino - Sample Arduino sketches to show how payload sensors can be interfaced to CubeSat Simulator - - ax5043 - Source for a library of functions to communicate with the AX5043 and configure the AX5043. - - cw - Code that sends telemetry in CW (Morse code) using AO-7 format - - libs - External libraries - - python - Python code for reading I2C sensors for current and temperature - - spreadsheet - Spreadsheets for decoding and analyzing the Simulator telemetry (see https://github.com/alanbjohnston/CubeSatSim/wiki/Decoding-Telemetry for details) - - wav - Wave audio files of CW or AFSK telemetry for listening or transmitting usng a CubeSat Simulator Lite - - demo.sh - a shell script to run the Simulator on boot using systemd (see https://github.com/alanbjohnston/CubeSatSim/wiki/Software-Install#autoboot-configuration for how to configure the Pi) +`sudo make install` + +`make install-rpi` + +Note that this last command may fail if you are using Raspbian Lite since there is no Desktop (you may get an error such as this "ln: failed to create symbolic link '/home/pi/Desktop/direwolf.desktop': No such file or directory +make: *** [Makefile.linux:727: install-rpi] Error 1" + +`cd` + +`git clone https://github.com/F5OEO/rpitx.git` + +`cd rpitx` + +`./install.sh` + +(Takes a while). It will prompt you if you want to modify /boot/config.txt file. Type a `y` and the script will complete. + +`cd` + +`git clone https://github.com/alanbjohnston/pi-power-button.git` + +`cd pi-power-button` + +`./script/install` + +To make the demo.sh script run automatically on boot: + +`sudo cp ~/CubeSatSim/systemd/cubesatsim.service /etc/systemd/system/cubesatsim.service` + +`sudo systemctl enable cubesatsim` + +Now reboot for all the changes to take effect: + +`sudo reboot now` + +After rebooting, tune your radio or SDR to 434.9 MHz FM, and you should receive telemetry from the CubeSatSim! + +You can stop the service: + +`sudo systemctl stop cubesatsim` + +After rebooting, it will start unless you disable it: + +`sudo systemctl disable cubesatsim` See the Wiki for more details https://github.com/alanbjohnston/CubeSatSim/wiki + +Older Versions + +There are several versions of the hardware and software to go with them: + +- The original design used a Digital Transceiver Board for the Raspberry Pi (DigitalTxRxRPi) and APRS AFSK 1200 bps telemetry only. Use the aprs-digitaltxrx branch for this and the vB2 wiki page https://github.com/alanbjohnston/CubeSatSim/wiki/vB2-Home +- An updated design that used the Transmitter/Filter Board (TFB) instead of the the Transceiver Board. For the same APRS AFSK telemetry, use the aprs-rpitx branch and the vB3 wiki page https://github.com/alanbjohnston/CubeSatSim/wiki/vB3-Home. Note that this hardware can still use the master code branch. diff --git a/afsk/Adafruit_INA219.h b/afsk/Adafruit_INA219.h new file mode 100644 index 00000000..1e8c0c63 --- /dev/null +++ b/afsk/Adafruit_INA219.h @@ -0,0 +1,154 @@ +/*! + * @file Adafruit_INA219.h + * + * This is a library for the Adafruit INA219 breakout board + * ----> https://www.adafruit.com/products/904 + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Kevin "KTOWN" Townsend for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + * Converted to C for Raspberry Pi by Alan Johnston KU2Y + * + */ + +#include + +/** default I2C address **/ +#define INA219_ADDRESS (0x40) // 1000000 (A0+A1=GND) + +/** read **/ +#define INA219_READ (0x01) + +/*========================================================================= + CONFIG REGISTER (R/W) +**************************************************************************/ + +/** config register address **/ +#define INA219_REG_CONFIG (0x00) + +/** reset bit **/ +#define INA219_CONFIG_RESET (0x8000) // Reset Bit + +/** mask for bus voltage range **/ +#define INA219_CONFIG_BVOLTAGERANGE_MASK (0x2000) // Bus Voltage Range Mask + +/** bus voltage range values **/ +enum { + INA219_CONFIG_BVOLTAGERANGE_16V = (0x0000), // 0-16V Range + INA219_CONFIG_BVOLTAGERANGE_32V = (0x2000), // 0-32V Range +}; + +/** mask for gain bits **/ +#define INA219_CONFIG_GAIN_MASK (0x1800) // Gain Mask + +/** values for gain bits **/ +enum { + INA219_CONFIG_GAIN_1_40MV = (0x0000), // Gain 1, 40mV Range + INA219_CONFIG_GAIN_2_80MV = (0x0800), // Gain 2, 80mV Range + INA219_CONFIG_GAIN_4_160MV = (0x1000), // Gain 4, 160mV Range + INA219_CONFIG_GAIN_8_320MV = (0x1800), // Gain 8, 320mV Range +}; + +/** mask for bus ADC resolution bits **/ +#define INA219_CONFIG_BADCRES_MASK (0x0780) + +/** values for bus ADC resolution **/ +enum { + INA219_CONFIG_BADCRES_9BIT = (0x0000), // 9-bit bus res = 0..511 + INA219_CONFIG_BADCRES_10BIT = (0x0080), // 10-bit bus res = 0..1023 + INA219_CONFIG_BADCRES_11BIT = (0x0100), // 11-bit bus res = 0..2047 + INA219_CONFIG_BADCRES_12BIT = (0x0180), // 12-bit bus res = 0..4097 +}; + +/** mask for shunt ADC resolution bits **/ +#define INA219_CONFIG_SADCRES_MASK \ + (0x0078) // Shunt ADC Resolution and Averaging Mask + +/** values for shunt ADC resolution **/ +enum { + INA219_CONFIG_SADCRES_9BIT_1S_84US = (0x0000), // 1 x 9-bit shunt sample + INA219_CONFIG_SADCRES_10BIT_1S_148US = (0x0008), // 1 x 10-bit shunt sample + INA219_CONFIG_SADCRES_11BIT_1S_276US = (0x0010), // 1 x 11-bit shunt sample + INA219_CONFIG_SADCRES_12BIT_1S_532US = (0x0018), // 1 x 12-bit shunt sample + INA219_CONFIG_SADCRES_12BIT_2S_1060US = + (0x0048), // 2 x 12-bit shunt samples averaged together + INA219_CONFIG_SADCRES_12BIT_4S_2130US = + (0x0050), // 4 x 12-bit shunt samples averaged together + INA219_CONFIG_SADCRES_12BIT_8S_4260US = + (0x0058), // 8 x 12-bit shunt samples averaged together + INA219_CONFIG_SADCRES_12BIT_16S_8510US = + (0x0060), // 16 x 12-bit shunt samples averaged together + INA219_CONFIG_SADCRES_12BIT_32S_17MS = + (0x0068), // 32 x 12-bit shunt samples averaged together + INA219_CONFIG_SADCRES_12BIT_64S_34MS = + (0x0070), // 64 x 12-bit shunt samples averaged together + INA219_CONFIG_SADCRES_12BIT_128S_69MS = + (0x0078), // 128 x 12-bit shunt samples averaged together +}; + +/** mask for operating mode bits **/ +#define INA219_CONFIG_MODE_MASK (0x0007) // Operating Mode Mask + +/** values for operating mode **/ +enum { + INA219_CONFIG_MODE_POWERDOWN, + INA219_CONFIG_MODE_SVOLT_TRIGGERED, + INA219_CONFIG_MODE_BVOLT_TRIGGERED, + INA219_CONFIG_MODE_SANDBVOLT_TRIGGERED, + INA219_CONFIG_MODE_ADCOFF, + INA219_CONFIG_MODE_SVOLT_CONTINUOUS, + INA219_CONFIG_MODE_BVOLT_CONTINUOUS, + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS +}; + +/** shunt voltage register **/ +#define INA219_REG_SHUNTVOLTAGE (0x01) + +/** bus voltage register **/ +#define INA219_REG_BUSVOLTAGE (0x02) + +/** power register **/ +#define INA219_REG_POWER (0x03) + +/** current register **/ +#define INA219_REG_CURRENT (0x04) + +/** calibration register **/ +#define INA219_REG_CALIBRATION (0x05) + +/*! + * functions for interacting with INA219 + * current/power monitor IC + */ + //void begin(TwoWire *theWire = &Wire); + void setCalibration_32V_2A(int fd); + void setCalibration_32V_1A(int fd); + void setCalibration_16V_400mA(int fd); + void setCalibration_16V_2A(int fd); + float getBusVoltage_V(int fd); + float getShuntVoltage_mV(int fd); + float getCurrent_mA(int fd); + float getPower_mW(int fd); + void powerSave(int fd, int on); + + uint8_t ina219_i2caddr; + //uint32_t ina219_calValue; + uint16_t ina219_calValue; + uint16_t ina219_config; + // The following multipliers are used to convert raw current and power + // values to mA and mW, taking into account the current config settings + uint32_t ina219_currentDivider_mA; + float ina219_powerMultiplier_mW; + + void init(); + void wireWriteRegister(int fd, uint8_t reg, uint16_t value); + uint16_t wireReadRegister(int fd, uint8_t reg); + int16_t getBusVoltage_raw(int fd); + int16_t getShuntVoltage_raw(int fd); + int16_t getCurrent_raw(int fd); + int16_t getPower_raw(int fd); diff --git a/afsk/ax25.c b/afsk/ax25.c index 15b127c2..a3de7ba5 100644 --- a/afsk/ax25.c +++ b/afsk/ax25.c @@ -18,8 +18,11 @@ * along with this program. If not, see . */ +//#include #include "ax25.h" #include +#include +#include #include "ax5043.h" #include "status.h" @@ -88,6 +91,51 @@ int ax25_tx_frame(ax25_conf_t *hax25, ax5043_conf_t *hax, memcpy(__tx_buffer, hax25->addr_field, hax25->addr_field_len); memcpy(__tx_buffer + hax25->addr_field_len, payload, len); + +#ifdef SATNOGS + printf("\n"); + char post_data[1024]; + char hex_data[512]; + char hex_octet[4]; + time_t t = time(NULL); + struct tm tm = *localtime(&t); + memset(post_data,0,strlen(post_data)); + memset(hex_data,0,strlen(hex_data)); + //printf("1:%s\n",post_data); + + int jj; + for(jj = 0; jj < 118; jj++) { + sprintf(hex_octet, "%02x",__tx_buffer[jj]); + strcat(hex_data, hex_octet); + } // Note assumes EDT, change offset (+4) to UTC +/* + sprintf(post_data,"noradID=99999&source=KU2Y×tamp=%d-%d-%dT%d:%d:%d.500Z&frame=%s&locator=longLat&longitude=75.3492W&latitude=40.0376N&&azimuth=360&elevation=90.0", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, (tm.tm_hour + 4) % 24, tm.tm_min, tm.tm_sec, hex_data); + + printf("curl post data: %s\n",post_data); + + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if(curl) { + //curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); + curl_easy_setopt(curl, CURLOPT_URL, "https://db.satnogs.org/api/telemetry/"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(post_data)); + + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + + res = curl_easy_perform(curl); + if(res != CURLE_OK) + fprintf(stderr, "ERROR: AX25.C curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + curl_easy_cleanup(curl); + } + */ +#endif return ax5043_tx_frame(hax, __tx_buffer, len + hax25->addr_field_len, hax25->preamble_len, hax25->postable_len, 1000); diff --git a/afsk/ax5043.c b/afsk/ax5043.c index 8ed001f5..f8c3b2e9 100644 --- a/afsk/ax5043.c +++ b/afsk/ax5043.c @@ -1071,7 +1071,9 @@ int ax5043_wait_for_transmit() { /* tx is done */ __tx_frame_end(__ax5043_conf); transmittedPostamble = 0; - printf("INFO: TX done\n"); + #ifdef DEBUG_LOGGING + printf("INFO: TX done\n"); + #endif return PQWS_SUCCESS; } @@ -1130,7 +1132,9 @@ int ax5043_wait_for_transmit() { if (radiostate == 0) { /* tx is done */ __tx_active = 0; - printf("INFO: TX done\n"); + #ifdef DEBUG_LOGGING + printf("INFO: TX done\n"); + #endif } } } diff --git a/afsk/ax5043.c.bk b/afsk/ax5043.c.bk deleted file mode 100644 index f5b31b91..00000000 --- a/afsk/ax5043.c.bk +++ /dev/null @@ -1,1162 +0,0 @@ -/* - * A sample application transmitting AFSK 1200 baud - * - * Portions Copyright (C) 2018 Libre Space Foundation - * Portions Copyright (C) 2018 Jonathan Brandenburg - * - * 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 "ax25.h" -#include "ax5043.h" -#include "status.h" -#include "utils.h" -#include "spi/ax5043spi.h" - -static uint8_t single_fifo_access = 0; - -static uint8_t __tx_buf[MAX_FRAME_LEN]; -static size_t __tx_buf_idx = 0; -static uint8_t __tx_fifo_chunk[AX5043_FIFO_MAX_SIZE]; -static uint32_t __tx_remaining = 0; - -/** - * FIFO command for the preamble. The third byte corresponds the length of - * the preamble and is set by the TX routine for every frame - */ -static uint8_t __preamble_cmd[4] = { AX5043_FIFO_REPEATDATA_CMD, -AX5043_FIFO_PKTSTART | AX5043_FIFO_RAW | AX5043_FIFO_NOCRC, 0, -AX25_SYNC_FLAG }; - -/** - * FIFO command for the postable. The third byte corresponds the length of - * the postable and is set by the TX routine for every frame - */ -static uint8_t __postamble_cmd[4] = { -AX5043_FIFO_REPEATDATA_CMD, -AX5043_FIFO_PKTSTART | AX5043_FIFO_PKTEND | AX5043_FIFO_RAW | AX5043_FIFO_NOCRC, - 0, AX25_SYNC_FLAG }; - -/** - * Indicates if a TX is currently active - */ -static volatile uint8_t __tx_active = 0; - -static ax5043_conf_t *__ax5043_conf = NULL; - -static inline int set_tx_black_magic_regs(); - -/** - * Checks if the AX5043 handler is valid - * @param conf the AX5043 configuration handler pointer - * @return 1 if it is valid 0 otherwise - */ -static uint8_t is_ax5043_conf_valid(ax5043_conf_t *conf) { - if (!conf || !conf->f_xtal) { - return 0; - } - return 1; -} - -/** - * Resets the AX5043 - * @param conf the AX5043 configuration handler - * @return 0 on success or appropriate negative error code - */ -int ax5043_reset_a(ax5043_conf_t *conf) { - int ret; - uint8_t val; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - conf->rf_init = 0; - usleep(100); - - /* Reset the chip using the appropriate register */ - val = BIT(7); - ret = ax5043_spi_write_8(conf, AX5043_REG_PWRMODE, val); - if (ret) { - return ret; - } - usleep(100); - /* Clear the reset bit, but keep REFEN and XOEN */ - ret = ax5043_spi_read_8(conf, &val, AX5043_REG_PWRMODE); - if (ret) { - return ret; - } - val &= (BIT(6) | BIT(5)); - ret = ax5043_spi_write_8(conf, AX5043_REG_PWRMODE, val); - if (ret) { - return ret; - } - usleep(100); - - ret = ax5043_set_power_mode(conf, POWERDOWN); - if (ret) { - return ret; - } - return PQWS_SUCCESS; -} - -/** - * Initialization routine for the AX5043 IC - * @param conf the AX5043 configuration handler - * @param spi the SPI handler - * @param f_xtal the frequency of the crystal or the TCXO - * @param vco the VCO mode - * @return 0 on success or appropriate negative error code - */ -int ax5043_init(ax5043_conf_t *conf, uint32_t f_xtal, vco_mode_t vco) { - int ret; - uint8_t revision; - uint8_t val; - printf("1 \n"); - - if (!conf) { - return -PQWS_INVALID_PARAM; - } - - /* Set the initial parameters */ - memset(conf, 0, sizeof(ax5043_conf_t)); - printf("2\n "); - switch (vco) { - case VCO_INTERNAL: - case VCO_EXTERNAL: - conf->vco = vco; - break; - default: - return -PQWS_INVALID_PARAM; - } - - conf->rf_init = 0; - conf->freqsel = -1; - conf->f_xtal = f_xtal; - if (conf->f_xtal > 24800000) { - conf->f_xtaldiv = 2; - } else { - conf->f_xtaldiv = 1; - } - printf("3\n "); - - ret = ax5043_reset_a(conf); - printf("4 \n"); - if (ret) { - return ret; - } - printf("5\n "); - - /* Try first to read the revision register of the AX5043 */ - ret = ax5043_spi_read_8(conf, &revision, AX5043_REG_REV); - printf("6 \n"); - if (ret) { - return ret; - } - - if (revision != AX5043_REV) { - return -PQWS_NO_RF_FOUND; - } - - /* To ensure communication try to write and read the scratch register */ - val = AX5043_SCRATCH_TEST; - printf("7 \n"); - ret = ax5043_spi_write_8(conf, AX5043_REG_SCRATCH, val); - printf("8 \n"); - if (ret) { - return ret; - } - - val = 0x0; - printf("9 \n"); - ret = ax5043_spi_read_8(conf, &val, AX5043_REG_SCRATCH); - printf("10 \n"); - if (ret) { - return ret; - } - - if (val != AX5043_SCRATCH_TEST) { - return -PQWS_NO_RF_FOUND; - } - - printf("11 \n"); - ret = ax5043_set_pll_params(conf); - printf("12 \n"); - if (ret) { - return ret; - } - - /* Write the performance register F35 based on the XTAL frequency */ - printf("13 \n"); - if (conf->f_xtaldiv == 1) { - ret = ax5043_spi_write_8(conf, 0xF35, 0x10); - } else { - ret = ax5043_spi_write_8(conf, 0xF35, 0x11); - } - printf("14 \n"); - if (ret) { - return ret; - } - - /* FIFO maximum chunk */ - printf("15 \n"); - ret = ax5043_spi_write_8(conf, AX5043_REG_PKTCHUNKSIZE, - AX5043_PKTCHUNKSIZE_240); - printf("15 \n"); - if (ret) { - return ret; - } - - /* Set RF parameters */ - printf("16 \n"); - ret = ax5043_freqsel(conf, FREQA_MODE); - printf("17 \n"); - if (ret) { - return ret; - } - - /* - * We use APRS for all transmitted frames. APRS is encapsulated in a - * AX.25 frame. For 9600 baudrate is FSK9600 G3RUH compatible modem - */ - printf("18 \n"); - ret = ax5043_aprs_framing_setup(conf); - printf("19 \n"); - if (ret) { - return ret; - } - - /* Setup TX only related parameters */ - printf("20 \n"); - ret = ax5043_conf_tx_path(conf); - printf("21 \n"); - if (ret) { - return ret; - } - - /* Set an internal copy for the ax5042_wait_for_transmit function */ - __ax5043_conf = conf; - - if (ret) { - return ret; - } - printf("22 \n"); - ax5043_enable_pwramp(conf, AX5043_EXT_PA_DISABLE); - printf("23 \n"); - return PQWS_SUCCESS; -} - -/** - * Performs TX specific configuration of the AX5043 - * @param conf the AX5043 configuration handler - * @return 0 on success or appropriate negative error code - */ -int ax5043_conf_tx_path(ax5043_conf_t *conf) { - printf("25 \n"); - int ret; - - printf("26 \n"); - ret = ax5043_set_tx_synth(conf); - printf("27 \n"); - if (ret) { - return ret; - } - - printf("28 \n"); - ret = ax5043_set_tx_baud(conf, TX_BAUDRATE); - printf("29 \n"); - if (ret) { - return ret; - } - - // printf("30 \n"); - ret = ax5043_set_tx_freq(conf, TX_FREQ_HZ); - printf("31\n "); - if (ret) { - return ret; - } - - /* Our TX is on single ended mode */ - //ret = ax5043_spi_write_8(conf, AX5043_REG_MODCFGA, - //AX5043_TX_SINGLE_ENDED); - //if (ret) { - // return ret; - //} - - /* Our TX is on double ended mode */ - printf("32 \n"); - ret = ax5043_spi_write_8(conf, AX5043_REG_MODCFGA, - AX5043_TX_DIFFERENTIAL); - printf("33 \n"); - if (ret) { - return ret; - } - - /* Set the rest of the performance registers for TX */ - printf("34 \n"); - ret = set_tx_black_magic_regs(conf); - printf("35 \n"); - if (ret) { - return ret; - } - - /* - * As our board has an external PA, reduce the output power to reduce - * the excess bandwidth emissions - */ - //ret = ax5043_spi_write_16(conf, AX5043_REG_TXPWRCOEFFB1, 0x01FF); - //if (ret) { - //return ret; - //} - - // Not using a PA, transmit half power - printf("36 \n"); - ret = ax5043_spi_write_16(conf, AX5043_REG_TXPWRCOEFFB1, 0x07FF); - printf("37 \n"); - if (ret) { - return ret; - } - - return PQWS_SUCCESS; -} - -/** - * Sets the power mode of the AX5043 - * @param conf the AX5043 configuration handler - * @param mode the power mode - * @return 0 on success or appropriate negative error code - */ -int ax5043_set_power_mode(ax5043_conf_t *conf, power_mode_t mode) { - int ret; - uint8_t val; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - /* Read the contents of the register */ - ret = ax5043_spi_read_8(conf, &val, AX5043_REG_PWRMODE); - if (ret) { - return ret; - } - - /* Keep REFEN and XOEN values */ - val &= (BIT(6) | BIT(5)); - - switch (mode) { - case POWERDOWN: - val |= AX5043_POWERDOWN; - break; - case DEEPSLEEP: - val |= AX5043_DEEPSLEEP; - break; - case STANDBY: - val |= AX5043_STANDBY; - break; - case FIFO_ENABLED: - val |= AX5043_FIFO_ENABLED; - break; - case RECEIVE_MODE: - val |= AX5043_RECEIVE_MODE; - break; - case RECEIVER_RUNNING: - val |= AX5043_RECEIVER_RUNNING; - break; - case RECEIVER_WOR: - val |= AX5043_RECEIVER_WOR; - break; - case TRANSMIT_MODE: - val |= AX5043_TRANSMIT_MODE; - break; - case FULLTX: - val |= AX5043_FULLTX; - break; - default: - return -PQWS_INVALID_PARAM; - } - return ax5043_spi_write_8(conf, AX5043_REG_PWRMODE, val); -} - -/** - * Sets the RF frequency of the TX. If the previous TX frequency is - * further enough than the new one, this function performs automatically - * auto-ranging. - * - * @param conf the AX5043 configuration handler - * @param freq the target RF frequency - * @return 0 on success or appropriate negative error code - */ -int ax5043_set_tx_freq(ax5043_conf_t *conf, uint32_t freq) { - int ret; - uint32_t prev_freq; - uint32_t reg_val; - uint8_t rfdiv = 0; - uint8_t pllcodediv = 0; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - /* Check the frequency range. The actual range depends on the VCO used */ - switch (conf->vco) { - case VCO_INTERNAL: - if (freq >= MIN_RF_FREQ_INT_VCO_RFDIV0 - && freq <= MAX_RF_FREQ_INT_VCO_RFDIV0) { - rfdiv = AX5043_RFDIV0; - } else if (freq >= MIN_RF_FREQ_INT_VCO_RFDIV1 - && freq <= MAX_RF_FREQ_INT_VCO_RFDIV1) { - rfdiv = AX5043_RFDIV1; - } else { - return -PQWS_INVALID_PARAM; - } - break; - case VCO_EXTERNAL: - fprintf(stderr, "ERROR: Unexpected use of external VCO\n"); - if (freq >= MIN_RF_FREQ_EXT_VCO_RFDIV0 - && freq <= MAX_RF_FREQ_EXT_VCO_RFDIV0) { - rfdiv = AX5043_RFDIV0; - } else if (freq >= MIN_RF_FREQ_EXT_VCO_RFDIV1 - && freq <= MAX_RF_FREQ_EXT_VCO_RFDIV1) { - rfdiv = AX5043_RFDIV1; - } else { - return -PQWS_INVALID_PARAM; - } - break; - default: - return -PQWS_INVALID_PARAM; - } - prev_freq = conf->tx_freq; - pllcodediv = rfdiv | (uint8_t) (conf->vco << 4); - - // Added by Jonathan Brandenburg - // Have an external inductor - pllcodediv |= BIT(5); - - ret = ax5043_spi_write_8(conf, AX5043_REG_PLLVCODIV, pllcodediv); - if (ret) { - return ret; - } - - /* Write properly the F34 performance register based on the RFDIV*/ - if (rfdiv == AX5043_RFDIV1) { - ret = ax5043_spi_write_8(conf, 0xF34, 0x28); - } else { - ret = ax5043_spi_write_8(conf, 0xF34, 0x08); - } - if (ret) { - return ret; - } - - /* - * Set the RF frequency - * Frequency should be avoided to be a multiple integer of the crystal - * frequency, so we always set to 1 the LSB - */ - reg_val = ((uint32_t) (((float) freq / (float) conf->f_xtal) * (1 << 24)) - | 0x1); - if (conf->freqsel == FREQA_MODE) { - ret = ax5043_spi_write_32(conf, AX5043_REG_FREQA3, reg_val); - } else { - ret = ax5043_spi_write_32(conf, AX5043_REG_FREQB3, reg_val); - } - if (ret) { - return ret; - } - - /* Considered that the frequency successfully changed */ - conf->tx_freq = freq; - - /* If the frequency difference is great enough perform autoranging */ - if (freq + 25000000 > prev_freq || freq - 25000000 < prev_freq) { - ax5043_autoranging(conf); - } - - return PQWS_SUCCESS; -} - -/** - * Set the TX baudrate - * @param conf the AX5043 configuration handler - * @param baud the baudrate - * @return 0 on success or negative error code - */ -int ax5043_set_tx_baud(ax5043_conf_t *conf, uint32_t baud) { - int ret = PQWS_SUCCESS; - uint32_t val; - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - val = (uint32_t) ((((float) baud) / (float) conf->f_xtal) * (1 << 24)) - | 0x1; - ret = ax5043_spi_write_24(conf, AX5043_REG_TXRATE2, val); - if (ret) { - return ret; - } - - conf->tx_baudrate = baud; - - /* Set the deviation to standard 3 KHz for FM */ - // For AFSK, FSKDEV = 0.858785 * fDeviation / fXTAL * 2^24 - // - val = (uint32_t) ((0.858785 * 3000.0f / (float) conf->f_xtal) * (1 << 24)) - | 0x1; - ret = ax5043_spi_write_24(conf, AX5043_REG_FSKDEV2, val); - if (ret) { - return ret; - } - - return PQWS_SUCCESS; -} - -/** - * Sets the currently used frequency registers (A or B) - * @param conf the AX5043 configuration handler - * @param f the frequency mode (A or B) - * @return 0 on success or appropriate negative error code - */ -int ax5043_freqsel(ax5043_conf_t *conf, freq_mode_t f) { - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - if (f != FREQA_MODE && f != FREQB_MODE) { - return -PQWS_INVALID_PARAM; - } - conf->freqsel = f; - return PQWS_SUCCESS; -} - -/** - * Sets the TX frequency synthesizer related configuration registers. - * @param conf the AX5043 configuration handler - * @return 0 on success or appropriate negative error code - */ -int ax5043_set_tx_synth(ax5043_conf_t *conf) { - int ret; - uint8_t val; - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - switch (conf->freqsel) { - case FREQA_MODE: - val = 0x0; - break; - case FREQB_MODE: - val = 1 << 7; - break; - default: - return -PQWS_INVALID_PARAM; - } - - /* Bypass external filter and use 100 kHZ loop bandwidth */ - val |= BIT(3) | BIT(0); - ret = ax5043_spi_write_8(conf, AX5043_REG_PLLLOOP, val); - if (ret) { - return ret; - } - - /* - * Set the charge pump current based on the loop bandwidth - * 68 uA @ 100 kHZ - */ - ret = ax5043_spi_write_8(conf, AX5043_REG_PLLCPI, (uint8_t) (68 / 8.5)); - if (ret) { - return ret; - } - ret = ax5043_spi_write_8(conf, AX5043_REG_XTALCAP, 0); - return ret; -} - -/** - * Sets the PLL related configuration registers. - * @param conf the AX5043 configuration handler - * @return 0 on success or appropriate negative error code - */ -int ax5043_set_pll_params(ax5043_conf_t *conf) { - int ret; - uint8_t i = 8; - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - /* Set VCO to manual */ - ret = ax5043_spi_write_8(conf, AX5043_REG_PLLVCOI, - AX5043_PLLVCOI_MANUAL | (1250 / 50)); - if (ret) { - return ret; - } - - /* - * According to the manual PLL ranging clock should be less than 1/10 - * of the PLL loop bandwidth. The smallest PLL bandwidth configuration - * is 100 kHz. - */ - // This this next line contains an error - //while (conf->f_xtal / (uint32_t) (1 << i) > 10000) { - while (conf->f_xtal / (uint32_t) (1 << i) > 100000) { - i++; - } - i = i > 15 ? 15 : i; - i = i < 8 ? 8 : i; - ret = ax5043_spi_write_8(conf, AX5043_REG_PLLRNGCLK, (uint8_t) (i - 8)); - return ret; -} - -/** - * Performs auto-ranging using the frequency registers configured by - * ax5043_freqsel(). - * - * @param conf the AX5043 configuration handler - * @return 0 on success or appropriate negative error code - */ -int ax5043_autoranging(ax5043_conf_t *conf) { - int ret = PQWS_SUCCESS; - uint16_t pllranging_reg; - uint8_t val = 0; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - switch (conf->freqsel) { - case FREQA_MODE: - pllranging_reg = AX5043_REG_PLLRANGINGA; - break; - case FREQB_MODE: - pllranging_reg = AX5043_REG_PLLRANGINGB; - break; - default: - return -PQWS_INVALID_PARAM; - } - - /* Write the initial VCO setting and start autoranging */ - val = BIT(4) | AX5043_VCOR_INIT; - ret = ax5043_spi_write_8(conf, pllranging_reg, val); - if (ret) { - return ret; - } - - usleep(10); - val = 0; - /* Wait until the autoranging is complete */ - while ((val & BIT(4)) == 0) { - ret = ax5043_spi_read_8(conf, &val, pllranging_reg); - if (ret) { - return ret; - } - } - - if (val & BIT(5)) { - return -PQWS_AX5043_AUTORANGING_ERROR; - } - - return PQWS_SUCCESS; -} - -/** - * - * @param conf the AX5043 configuration handler - * @return 0 on success or appropriate negative error code - */ -int ax5043_aprs_framing_setup(ax5043_conf_t *conf) { - int ret = PQWS_SUCCESS; - uint8_t val = 0; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - /* Set modulation */ - val = AX5043_MODULATION_AFSK; - ret = ax5043_spi_write_8(conf, AX5043_REG_MODULATION, val); - if (ret) { - return ret; - } - - // To set the space frequency, 1070 - // 1070 * 2^18 / fXTAL -> 1070 * 2^18 / 16000000 -> 18 -> 0x12 - - // To set the space frequency, 1200 - // 1200 * 2^18 / fXTAL -> 1200 * 2^18 / 16000000 -> 20 -> 0x14 - - ret = ax5043_spi_write_16(conf, AX5043_REG_AFSKSPACE1, 0x24); - if (ret) { - return ret; - } - - // To set the mark frequency, 1270 - // 1270 * 2^18 / fXTAL -> 1270 * 2^18 / 16000000 -> 21 -> 0x15 - - // To set the mark frequency, 1400 - // 1400 * 2^18 / fXTAL -> 1400 * 2^18 / 16000000 -> 23 -> 0x17 - - ret = ax5043_spi_write_16(conf, AX5043_REG_AFSKMARK1, 0x14); - if (ret) { - return ret; - } - - /* - * As we do not use any external filter, try to filter from - * the AX5043 the signal - */ - ret = ax5043_spi_write_8(conf, AX5043_REG_MODCFGF, - AX5043_FREQSHAPE_GAUSSIAN_BT_05); - if (ret) { - return ret; - } - - /* Set HDLC encoding: Differential = 1, Inverse = 1, Scrambling = 1 */ - //ax5043_spi_write_8(conf, AX5043_REG_ENCODING, - /* Set HDLC encoding: Differential = 1, Inverse = 1, Scrambling = 1 */ - ax5043_spi_write_8(conf, AX5043_REG_ENCODING, - AX5043_ENC_DIFF | AX5043_ENC_INV); - - /* HDLC framing */ - ax5043_spi_write_8(conf, AX5043_REG_FRAMING, - AX5043_HDLC_FRAMING | AX5043_CRC16_CCITT); - return ret; -} - -static int __tx_frame_end(ax5043_conf_t *conf) { - int ret; - - ax5043_enable_pwramp(conf, AX5043_EXT_PA_DISABLE); - - /* Set AX5043 to power down mode */ - ret = ax5043_set_power_mode(conf, POWERDOWN); - __tx_active = 0; - return ret; -} - -static int __tx_frame(ax5043_conf_t *conf, const uint8_t *in, uint32_t len, - uint8_t preamble_len, uint8_t postamble_len, uint32_t timeout_ms) { - int ret = PQWS_SUCCESS; - uint8_t data_cmd[3] = { AX5043_FIFO_VARIABLE_DATA_CMD, 0, 0 }; - size_t chunk_size = 0; - size_t avail; - uint8_t val; - uint32_t start = millis(); - - /* - * Apply preamble and postamble repetition length. Rest of the fields should - * remain unaltered - */ - __preamble_cmd[2] = preamble_len; - __postamble_cmd[2] = postamble_len; - - memcpy(__tx_fifo_chunk, __preamble_cmd, sizeof(__preamble_cmd)); - chunk_size = sizeof(__preamble_cmd); - __tx_buf_idx = 0; - - /* - * Always leave some space for the postamble. This greatly reduces the - * complexity of dealing with some corner cases - */ - avail = min_ul( - AX5043_FIFO_MAX_SIZE - sizeof(__preamble_cmd) - sizeof(data_cmd) - - sizeof(__postamble_cmd), len); - if (len == avail) { - data_cmd[1] = (uint8_t) (len + 1); - data_cmd[2] = AX5043_FIFO_PKTEND; - __tx_remaining = 0; - memcpy(__tx_fifo_chunk + chunk_size, data_cmd, sizeof(data_cmd)); - chunk_size += sizeof(data_cmd); - memcpy(__tx_fifo_chunk + chunk_size, in, len); - chunk_size += len; - /* - * At this point we are sure that the whole frame + postamble can fit in - * the FIFO chunk - */ - memcpy(__tx_fifo_chunk + chunk_size, __postamble_cmd, - sizeof(__postamble_cmd)); - chunk_size += sizeof(__postamble_cmd); - single_fifo_access = 1; - } else { - data_cmd[1] = (uint8_t) (avail + 1); - data_cmd[2] = 0; - memcpy(__tx_fifo_chunk + chunk_size, data_cmd, sizeof(data_cmd)); - chunk_size += sizeof(data_cmd); - memcpy(__tx_fifo_chunk + chunk_size, in, avail); - chunk_size += avail; - - memcpy(__tx_buf, in + avail, len - avail); - __tx_remaining = (uint32_t) (len - avail); - single_fifo_access = 0; - } - - /* Set AX5043 to FULLTX mode */ - ret = ax5043_set_power_mode(conf, FULLTX); - if (ret) { - return ret; - } - - ax5043_spi_wait_xtal(conf, 100); - - /* Wait for the FIFO to become ready */ - val = 0; - while (!val) { - ax5043_spi_read_8(conf, &val, AX5043_REG_POWSTAT); - /* Select only the modem power state */ - val &= AX5043_SVMODEM; - if (millis() - start > timeout_ms) { - ret = -PQWS_TIMEOUT; - break; - } - } - - /* Fire-up the first data to the FIFO */ - ret = ax5043_spi_write(conf, AX5043_REG_FIFODATA, __tx_fifo_chunk, - (uint32_t) chunk_size); - if (ret) { - return ret; - } - __tx_active = 1; - /* Commit to FIFO ! */ - ret = ax5043_spi_write_8(conf, AX5043_REG_FIFOSTAT, AX5043_FIFO_COMMIT_CMD); - - return ret; -} - -int ax5043_tx_frame(ax5043_conf_t *conf, const uint8_t *in, uint32_t len, - uint8_t preamble_len, uint8_t postamble_len, uint32_t timeout_ms) { - int ret = 0; - - /* Wait for the previous frame to be transmitted */ - while (__tx_active) { - ret++; - } - - ret = ax5043_enable_pwramp(conf, AX5043_EXT_PA_ENABLE); - if (ret) { - return ret; - } - - ret = __tx_frame(conf, in, len, preamble_len, postamble_len, timeout_ms); - return ret; -} - -/** - * Wait the crystal to become ready - * @param conf the AX5043 configuration handler - * @param timeout_ms the timeout in milliseconds - * @return 0 on success or appropriate negative error code - */ -int ax5043_spi_wait_xtal(ax5043_conf_t *conf, uint32_t timeout_ms) { - int ret; - uint8_t val = 0x0; - uint32_t start = millis(); - - while (!val) { - ret = ax5043_spi_read_8(conf, &val, AX5043_REG_XTALSTATUS); - if (ret) { - return ret; - } - if ((millis() - start) > timeout_ms) { - return -PQWS_TIMEOUT; - } - } - return 0; -} - -int ax5043_spi_read_8(ax5043_conf_t *conf, uint8_t *out, uint16_t reg) { - int ret = PQWS_SUCCESS; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - *out = ax5043ReadReg(reg); - - return ret; -} - -int ax5043_spi_read_16(ax5043_conf_t *conf, uint16_t *out, uint16_t reg) { - int ret = PQWS_SUCCESS; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - *out = ax5043ReadReg2(reg); - - return ret; -} - -int ax5043_spi_read_24(ax5043_conf_t *conf, uint32_t *out, uint16_t reg) { - int ret = PQWS_SUCCESS; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - *out = ax5043ReadReg3(reg); - - return ret; -} - -int ax5043_spi_read_32(ax5043_conf_t *conf, uint32_t *out, uint16_t reg) { - int ret = PQWS_SUCCESS; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - *out = ax5043ReadReg4(reg); - - return ret; -} - -int ax5043_spi_write(ax5043_conf_t *conf, uint16_t reg, const uint8_t *in, - uint32_t len) { - int ret = PQWS_SUCCESS; - - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - ax5043WriteRegN(reg, in, len); - - return ret; -} - -int ax5043_spi_write_8(ax5043_conf_t *conf, uint16_t reg, uint8_t in) { - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - //printf("Reg\t%04x\t%02x\n", reg, in); - - ax5043WriteReg(reg, in); - - return PQWS_SUCCESS; -} - -int ax5043_spi_write_16(ax5043_conf_t *conf, uint16_t reg, uint16_t in) { - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - //printf("Reg\t%04x\t%02x\n", reg, (in >> 8)&0xFF); - //printf("Reg\t%04x\t%02x\n", reg+1, (in >> 0)&0xFF); - - ax5043WriteReg2(reg, in); - - return PQWS_SUCCESS; -} - -int ax5043_spi_write_24(ax5043_conf_t *conf, uint16_t reg, uint32_t in) { - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - //printf("Reg\t%04x\t%02x\n", reg, (in >> 16)&0xFF); - //printf("Reg\t%04x\t%02x\n", reg+1, (in >> 8)&0xFF); - //printf("Reg\t%04x\t%02x\n", reg+2, (in >> 0)&0xFF); - - ax5043WriteReg3(reg, in); - - return PQWS_SUCCESS; -} - -int ax5043_spi_write_32(ax5043_conf_t *conf, uint16_t reg, uint32_t in) { - if (!is_ax5043_conf_valid(conf)) { - return -PQWS_INVALID_PARAM; - } - - //printf("Reg\t%04x\t%02x\n", reg, (in >> 24)&0xFF); - //printf("Reg\t%04x\t%02x\n", reg+1, (in >> 16)&0xFF); - //printf("Reg\t%04x\t%02x\n", reg+2, (in >> 8)&0xFF); - //printf("Reg\t%04x\t%02x\n", reg+3, (in >> 0)&0xFF); - - ax5043WriteReg4(reg, in); - - return PQWS_SUCCESS; -} - -/** - * Sets properly some undocumented TX registers - * @param conf the AX5043 configuration handler - * @return 0 on success or appropriate negative error code - */ -static inline int set_tx_black_magic_regs(ax5043_conf_t *conf) { - int ret; - ret = ax5043_spi_write_8(conf, 0xF00, 0x0F); - if (ret) { - return ret; - } - - ret = ax5043_spi_write_8(conf, 0xF0C, 0x0); - if (ret) { - return ret; - } - - // Added by Jonathan Brandenburg - ret = ax5043_spi_write_8(conf, 0xF0D, 0x03); - if (ret) { - return ret; - } - - // Added by Jonathan Brandenburg - ret = ax5043_spi_write_8(conf, 0xF10, 0x03); - if (ret) { - return ret; - } - - // The following line is used for a TCXO - //ret = ax5043_spi_write_8(conf, 0xF11, 0x0); - // The following line is used for a crystal - ret = ax5043_spi_write_8(conf, 0xF11, 0x07); - if (ret) { - return ret; - } - - ret = ax5043_spi_write_8(conf, 0xF1C, 0x07); - if (ret) { - return ret; - } - - ret = ax5043_spi_write_8(conf, 0xF44, 0x24); - if (ret) { - return ret; - } - - /* Dafuq? Got it from RadioLab */ - ret = ax5043_spi_write_8(conf, 0xF18, 0x06); - return ret; -} - -/** - * Enables/Disables the power amplifier pin - * @param conf the AX5043 configuration handler - * @param enable 1 to enable 0 to disable - * @return 0 on success or appropriate negative error code - */ -int ax5043_enable_pwramp(ax5043_conf_t *conf, uint8_t enable) { - int ret; - ax5043_set_antsel(conf, enable); - ret = ax5043_spi_write_8(conf, AX5043_REG_PWRAMP, ~enable & 0x1); - - if (ret) { - usleep(PWRAMP_RAMP_PERIOD_US); - } - return ret; -} - -int ax5043_set_antsel(ax5043_conf_t *conf, uint8_t val) { - return ax5043_spi_write_8(conf, AX5043_REG_PINFUNCANTSEL, val & 0x1); -} - -/** - * Wait for the AX5043 to finish transmitting, putting new data in the FIFO as space becomes available - * @return 0 on success, or appropriate negative error code - */ -int ax5043_wait_for_transmit() { - if (!single_fifo_access) { - while (__tx_active) { - static int transmittedPostamble = 0; - - //usleep(100); - - int ret; - uint8_t data_cmd[3] = { AX5043_FIFO_VARIABLE_DATA_CMD, 0, 0 }; - size_t avail; - size_t chunk_size; - - if (!__ax5043_conf) { - return -PQWS_INVALID_PARAM; - } - - /* Determine if TX is done */ - uint8_t radiostate = 0; - ret = ax5043_spi_read_8(__ax5043_conf, &radiostate, - AX5043_REG_RADIOSTATE); - if (ret) { - return ret; - } - radiostate &= 0x0f; - - if (radiostate == 0) { - /* tx is done */ - __tx_frame_end(__ax5043_conf); - transmittedPostamble = 0; - printf("INFO: TX done\n"); - return PQWS_SUCCESS; - } - - /* Determine FIFO free space */ - uint16_t fifofree = 0; - ret = ax5043_spi_read_16(__ax5043_conf, &fifofree, - AX5043_REG_FIFOFREE1); - if (ret) { - return ret; - } - - /* If FIFO has free space fill in data */ - if (fifofree > AX5043_FIFO_FREE_THR && (__tx_remaining || !transmittedPostamble)) { - - /* Always left some space for the postamble for a simplified logic */ - avail = min_ul( - AX5043_FIFO_FREE_THR - sizeof(data_cmd) - sizeof(__postamble_cmd), - __tx_remaining); - - data_cmd[1] = (uint8_t) (avail + 1); - chunk_size = sizeof(data_cmd) + avail; - memcpy(__tx_fifo_chunk + sizeof(data_cmd), __tx_buf + __tx_buf_idx, - avail); - - if (avail == __tx_remaining) { - transmittedPostamble = 1; - - data_cmd[2] = AX5043_FIFO_PKTEND; - memcpy(__tx_fifo_chunk + chunk_size, __postamble_cmd, - sizeof(__postamble_cmd)); - chunk_size += sizeof(__postamble_cmd); - } - memcpy(__tx_fifo_chunk, data_cmd, sizeof(data_cmd)); - ax5043_spi_write(__ax5043_conf, AX5043_REG_FIFODATA, - __tx_fifo_chunk, (uint32_t) chunk_size); - /* Commit to FIFO ! */ - ret = ax5043_spi_write_8(__ax5043_conf, AX5043_REG_FIFOSTAT, - AX5043_FIFO_COMMIT_CMD); - - __tx_remaining -= (uint32_t) avail; - __tx_buf_idx += avail; - - } - } - } else { - while (__tx_active) { - int ret; - /* Determine if TX is done */ - uint8_t radiostate = 0; - ret = ax5043_spi_read_8(__ax5043_conf, &radiostate, - AX5043_REG_RADIOSTATE); - if (ret) { - return ret; - } - radiostate &= 0x0f; - if (radiostate == 0) { - /* tx is done */ - __tx_active = 0; - printf("INFO: TX done\n"); - } - } - } - - return PQWS_SUCCESS; -} diff --git a/afsk/main.c b/afsk/main.c index 53730c90..54280c1d 100644 --- a/afsk/main.c +++ b/afsk/main.c @@ -1,5 +1,5 @@ /* - * Transmits CubeSat Telemetry at 440MHz in AO-7 format + * Transmits CubeSat Telemetry at 434.9MHz in AO-7 format * * Copyright Alan B. Johnston * @@ -7,7 +7,7 @@ * * 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 + * 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, @@ -17,12 +17,12 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * INA219 Raspberry Pi wiringPi code is based on Adafruit Arduino wire code + * from https://github.com/adafruit/Adafruit_INA219. */ -//#include //Needed for I2C port -#include //Needed for I2C port -//#include //Needed for I2C port - +#include #include #include #include @@ -33,245 +33,589 @@ #include "spi/ax5043spi.h" #include #include +#include #include -#include "ina219.h" - - -#define CALLSIGN "" // Put your callsign here! -#define VBATT 15 -#define ADC5 17 -#define ADC6 18 -#define ADC7 19 -#define ADC8 20 -#define TIME 8 -#define UCTEMP 30 -#define UPTIME_SEC 8 +#include +#include "Adafruit_INA219.h" // From Adafruit INA219 library for Arduino +#include "make_wav.h" +#include +#include +#include +#include +#include +#include + +#define PORT 8080 + #define A 1 #define B 2 #define C 3 #define D 4 -#define SENSOR_40 0 -#define SENSOR_41 3 -#define SENSOR_44 6 -#define SENSOR_45 9 -#define SENSOR_4A 12 -#define VOLTAGE 0 -#define CURRENT 1 -#define POWER 2 -#define VBATT 15 - -uint32_t tx_freq_hz = 440310000; +#define PLUS_X 0 +#define PLUS_Y 1 +#define PLUS_Z 2 +#define BAT 3 +#define MINUS_X 4 +#define MINUS_Y 5 +#define MINUS_Z 6 +#define BUS 7 +#define OFF -1 +#define ON 1 + +uint32_t tx_freq_hz = 434900000 + FREQUENCY_OFFSET; +uint8_t data[1024]; uint32_t tx_channel = 0; ax5043_conf_t hax5043; ax25_conf_t hax25; -static void init_rf(); -int get_tlm(int tlm[][5]); -long int timestamp; +int twosToInt(int val, int len); +int get_tlm(void); +int get_tlm_fox(); +int encodeA(short int *b, int index, int val); +int encodeB(short int *b, int index, int val); void config_x25(); void trans_x25(); -//long int timestamp; -int tempSensor; - int upper_digit(int number); int lower_digit(int number); -int charging = 0; +static int init_rf(); +int socket_open = 0; +int sock = 0; +int loop = -1, loop_count = 0; +int firstTime = ON; +long start; +int testCount = 0; -uint16_t config = (0x2000 | 0x1800 | 0x0180 | 0x0018 | 0x0007 ); +short int buffer[2336400]; // max size for 10 frames count of BPSK -int x_fd; // I2C bus 0 address 0x40 -int x_powerMultiplier; -int x_currentDivider; -int x_calValue_x; -int y_fd; // I2C bus 0 address 0x41 -int z_fd; // I2C bos 0 address 0x44 +#define S_RATE (48000) // (44100) +#define FSK 0 +#define BPSK 1 +#define AFSK 2 +int rpitxStatus = -1; -int main(void) { +float amplitude; // = ; // 20000; // 32767/(10%amp+5%amp+100%amp) +float freq_Hz = 3000; // 1200 + +int smaller; +int flip_ctr = 0; +int phase = 1; +int ctr = 0; +int rd = 0; +int nrd; +void write_to_buffer(int i, int symbol, int val); +void write_wave(int i, short int *buffer); - wiringPiSetup () ; - pinMode (0, OUTPUT) ; - int blink; - for (blink = 1; blink < 4 ;blink++) - { - digitalWrite (0, HIGH) ; delay (500) ; - digitalWrite (0, LOW) ; delay (500) ; - } - digitalWrite (0, HIGH) ; - - setSpiChannel(SPI_CHANNEL); - setSpiSpeed(SPI_SPEED); - initializeSpi(); +//#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (8 + 6 * DATA_LEN + 96)) * SAMPLES) +//#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN))) * SAMPLES) +//short int buffer[BUF_LEN]; +//short int data10[HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +//short int data8[HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +int reset_count; +float uptime_sec; +long int uptime; +char call[5]; - int tlm[7][5]; - memset(tlm, 0, sizeof tlm); +int bitRate, mode, bufLen, rsFrames, payloads, rsFrameLen, dataLen, headerLen, syncBits, syncWord, parityLen, samples, frameCnt, samplePeriod; +float sleepTime; +int sampleTime = 0; +int cycle = OFF, cw_id = ON; +int vB4 = FALSE, vB5 = FALSE, ax5043 = FALSE, onLed, onLedOn, onLedOff, txLed, txLedOn, txLedOff, payload = OFF; +float batteryThreshold = 0; - timestamp = time(NULL); - - int file_i2c; - //char *filenam1e = (char*)"/dev/i2c-3"; - if ((file_i2c = open("/dev/i2c-3", O_RDWR)) < 0) - { - fprintf(stderr,"ERROR: /dev/ic2-3 bus not present\n"); - tempSensor = -1; - } else - { - tempSensor = wiringPiI2CSetupInterface("/dev/i2c-3", 0x48); - } +struct SensorConfig { + int fd; + uint16_t config; + int calValue; + int powerMultiplier; + int currentDivider; +}; -// fprintf(stderr,"tempSensor: %d \n",tempSensor); +struct SensorData { + double current; + double voltage; + double power; +}; - int arduinoI2C; - if ((arduinoI2C = open("/dev/i2c-0", O_RDWR)) < 0) +/** + * @brief Read the data from one of the i2c current sensors. + * + * Reads the current data from the requested i2c current sensor configuration and + * stores it into a SensorData struct. An invalid file descriptor (i.e. less than zero) + * results in a SensorData struct being returned that has both its #current and #power members + * set to NAN. + * + * @param sensor A structure containing sensor configuration including the file descriptor. + * @return struct SensorData A struct that contains the current, voltage, and power readings + * from the requested sensor. + */ +struct SensorData read_sensor_data(struct SensorConfig sensor) { + struct SensorData data = { + .current = 0, + .voltage = 0, + .power = 0 }; + + if (sensor.fd < 0) { + return data; + } + // doesn't read negative currents accurately, shows -0.1mA + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CONFIG, sensor.config); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + sleep(0.01); + int value = wiringPiI2CReadReg16(sensor.fd, INA219_REG_CURRENT); + if (value == -1) { - fprintf(stderr,"ERROR: /dev/i2c-0 bus not present\n"); - } else { - arduinoI2C = wiringPiI2CSetupInterface("/dev/i2c-0", 0x4B); -// fprintf(stderr,"arduinoI2C: %d\n", arduinoI2C); - if (arduinoI2C > 0) { - if(wiringPiI2CReadReg16(arduinoI2C,0) < 0) { - arduinoI2C = -1; // Disable reading of Arduino payload information - fprintf(stderr,"Arduino payload not present\n"); - } - } else { - fprintf(stderr,"Arduino payload not present\n"); - } + sensor.fd = -1; + return data; } + data.current = (float) twosToInt(value, 16) / (float) sensor.currentDivider; + + wiringPiI2CWrite(sensor.fd, INA219_REG_BUSVOLTAGE); + delay(1); // Max 12-bit conversion time is 586us per sample + value = (wiringPiI2CRead(sensor.fd) << 8 ) | wiringPiI2CRead (sensor.fd); + data.voltage = ((float)(value >> 3) * 4) / 1000; + // power has very low resolution, seems to step in 512mW values + data.power = (float) wiringPiI2CReadReg16(sensor.fd, INA219_REG_POWER) * (float) sensor.powerMultiplier; + + return data; +} -// new INA219 current reading code - - x_calValue_x = 8192; - x_powerMultiplier = 1; - x_currentDivider = 20; - config = INA219_CONFIG_BVOLTAGERANGE_16V | - INA219_CONFIG_GAIN_40MV | - INA219_CONFIG_BADCRES_12BIT | - INA219_CONFIG_SADCRES_12BIT_4S_2130US | - //INA219_CONFIG_SADCRES_12BIT_1S_532US | - INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; - - if ((file_i2c = open("/dev/i2c-0", O_RDWR)) < 0) - { - fprintf(stderr,"ERROR: /dev/ic2-0 bus not present\n"); - x_fd = -1; // Disable reading -X, -Y, and -Z telemetry - y_fd = -1; - z_fd = -1; - } else - { - x_fd = wiringPiI2CSetupInterface("/dev/i2c-0", 0x40); -// fprintf(stderr,"Opening of -X fd %d\n", x_fd); - y_fd = wiringPiI2CSetupInterface("/dev/i2c-0", 0x41); -// printf("Opening of -Y fd %d\n", y_fd); - z_fd = wiringPiI2CSetupInterface("/dev/i2c-0", 0x44); -// printf("Opening of -Z fd %d\n", z_fd); +/** + * @brief Configures an i2c current sensor. + * + * Calculates the configuration values of the i2c sensor so that + * current, voltage, and power can be read using read_sensor_data. + * Supports 16V 400mA and 16V 2.0A settings. + * + * @param sensor A file descriptor that can be used to read from the sensor. + * @param milliAmps The mA configuration, either 400mA or 2A are supported. + * @return struct SensorConfig A struct that contains the configuraton of the sensor. + */ +//struct SensorConfig config_sensor(int sensor, int milliAmps) { +struct SensorConfig config_sensor(char *bus, int address, int milliAmps) { + struct SensorConfig data; + + if (access(bus, W_OK | R_OK) < 0) { // Test if I2C Bus is missing + printf("ERROR: %s bus not present \n", bus); + data.fd = OFF; + return (data); } - int ret; - uint8_t data[1024]; - - tx_freq_hz -= tx_channel * 50000; - - init_rf(); - -// ax25_init(&hax25, (uint8_t *) "CubeSatSim", '2', (uint8_t *) CALLSIGN, '2', - ax25_init(&hax25, (uint8_t *) "CQ", '1', (uint8_t *) CALLSIGN, '1', - AX25_PREAMBLE_LEN, - AX25_POSTAMBLE_LEN); - - - /* Infinite loop */ - for (;;) { - sleep(1); - - fprintf(stderr,"INFO: Getting TLM Data\n"); - - get_tlm(tlm); - - fprintf(stderr,"INFO: Preparing X.25 packet\n"); + data.fd = wiringPiI2CSetupInterface(bus, address); - char str[1000]; - char tlm_str[1000]; + data.config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_1_40MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_1S_532US | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + if (milliAmps == 400) { // INA219 16V 400mA configuration + data.calValue = 8192; + data.powerMultiplier = 1; + data.currentDivider = 20; // 40; in Adafruit config + } + else { // INA219 16V 2A configuration + data.calValue = 40960; + data.powerMultiplier = 2; + data.currentDivider = 10; // 20; in Adafruit config + } - char header_str[] = "\x03\xf0hi hi "; - strcpy(str, header_str); + #ifdef DEBUG_LOGGING + printf("Sensor %s %x configuration: %d %d %d %d %d\n", bus, address, data.fd, + data.config, data.calValue, data.currentDivider, data.powerMultiplier); + #endif + return data; +} + +struct SensorConfig sensor[8]; // 8 current sensors in Solar Power PCB vB4/5 +struct SensorData reading[8]; // 8 current sensors in Solar Power PCB vB4/5 +struct SensorConfig tempSensor; + +char src_addr[5] = ""; +char dest_addr[5] = "CQ"; + +int main(int argc, char *argv[]) { + + mode = FSK; + frameCnt = 1; - int channel; - for (channel = 1; channel < 7; channel++) { -// printf("%d %d %d %d \n", tlm[channel][1], tlm[channel][2], tlm[channel][3], tlm[channel][4]); - sprintf(tlm_str, "%d%d%d %d%d%d %d%d%d %d%d%d ", - channel, upper_digit(tlm[channel][1]), lower_digit(tlm[channel][1]), - channel, upper_digit(tlm[channel][2]), lower_digit(tlm[channel][2]), - channel, upper_digit(tlm[channel][3]), lower_digit(tlm[channel][3]), - channel, upper_digit(tlm[channel][4]), lower_digit(tlm[channel][4])); - printf("%s \n",tlm_str); - strcat(str, tlm_str); - } + if (argc > 1) { +// strcpy(src_addr, argv[1]); + if (*argv[1] == 'b') + { + mode = BPSK; + printf("Mode BPSK\n"); + } + else if (*argv[1] == 'a') + { + mode = AFSK; + printf("Mode AFSK\n"); + } + else if (*argv[1] == 'c') + { + cycle = ON; + printf("Mode cycle on\n"); + } + else + { + printf("Mode FSK\n"); + } - if (arduinoI2C > 0) { /* Read Arduino payload */ - for(int reg = 0; reg < 4; reg++) { - sprintf(tlm_str, " %04x",wiringPiI2CReadReg16(arduinoI2C,reg)); - printf("%s \n",tlm_str); - strcat(str,tlm_str); /* Append payload telemetry */ - usleep(100000); + if (argc > 2) { +// printf("String is %s %s\n", *argv[2], argv[2]); + loop = atoi(argv[2]); + loop_count = loop; } - } + printf("Looping %d times \n", loop); + + if (argc > 3) { + if (*argv[3] == 'n') + { + cw_id = OFF; + printf("No CW id\n"); + } + } + } + +// Open configuration file with callsign and reset count + FILE* config_file = fopen("/home/pi/CubeSatSim/sim.cfg","r"); + if (config_file == NULL) + { + printf("Creating config file."); + config_file = fopen("/home/pi/CubeSatSim/sim.cfg","w"); + fprintf(config_file, "%s %d", " ", 100); + fclose(config_file); + config_file = fopen("/home/pi/CubeSatSim/sim.cfg","r"); + } + + char* cfg_buf[100]; + fscanf(config_file, "%s %d", call, &reset_count); + fclose(config_file); + printf("Config file /home/pi/CubeSatSim/sim.cfg contains %s %d\n", call, reset_count); + reset_count = (reset_count + 1) % 0xffff; + + wiringPiSetup (); - digitalWrite (0, LOW); - -/* - char cmdbuffer[1000]; +// Check for SPI and AX-5043 Digital Transceiver Board + FILE *file = popen("sudo raspi-config nonint get_spi", "r"); + if (fgetc(file) == 48) + { + printf("SPI is enabled!\n"); + + file = popen("ls /dev/spidev0.* 2>&1", "r"); +// printf("Result: %d char: %c \n",file, getc(file)); - if (charging) { - FILE* file1 = popen("/home/pi/mopower/mpcmd LED_STAT=1", "r"); - fgets(cmdbuffer, 999, file1); - pclose(file1); + if (fgetc(file) != 'l') + { + printf("SPI devices present!\n"); -// printf("LED state: %s\n", cmdbuffer); - } -*/ - fprintf(stderr,"INFO: Transmitting X.25 packet\n"); - memcpy(data, str, strnlen(str, 256)); - ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); - if (ret) { - fprintf(stderr, - "ERROR: Failed to transmit AX.25 frame with error code %d\n", - ret); - exit(EXIT_FAILURE); - } - ax5043_wait_for_transmit(); - digitalWrite (0, HIGH); - -/* - FILE* file2 = popen("/home/pi/mopower/mpcmd LED_STAT=0", "r"); - fgets(cmdbuffer, 999, file2); - pclose(file2); +// } + + setSpiChannel(SPI_CHANNEL); + setSpiSpeed(SPI_SPEED); + initializeSpi(); +// char src_addr[5] = "KU2Y"; +// char dest_addr[5] = "CQ"; + ax25_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) call, '1', AX25_PREAMBLE_LEN, AX25_POSTAMBLE_LEN); + if (init_rf()) + { + printf("AX5043 successfully initialized!\n"); + ax5043 = TRUE; + cw_id = OFF; + mode = AFSK; + cycle = OFF; + printf("Mode AFSK with AX5043\n"); + } + else + printf("AX5043 not present!\n"); + } + } +// else +// { +// printf("SPI not enabled!\n"); +// } -// printf("LED state: %s\n", cmdbuffer); -*/ - if (ret) { - fprintf(stderr, - "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", - ret); - exit(EXIT_FAILURE); + txLed = 0; // defaults for vB3 board without TFB + txLedOn = LOW; + txLedOff = HIGH; + if (!ax5043) + { + pinMode (2, INPUT); + pullUpDnControl (2, PUD_UP); + + if (digitalRead(2) != HIGH) + { + printf("vB3 with TFB Present\n"); + txLed = 3; + txLedOn = LOW; + txLedOff = HIGH; + onLed = 0; + onLedOn = LOW; + onLedOff = HIGH; + } else + { + pinMode (3, INPUT); + pullUpDnControl (3, PUD_UP); + + if (digitalRead(3) != HIGH) + { + printf("vB4 Present\n"); + txLed = 2; + txLedOn = HIGH; + txLedOff = LOW; + vB4 = TRUE; + onLed = 0; + onLedOn = HIGH; + onLedOff = LOW; + batteryThreshold = 3.0; + } + else + { + pinMode (26, INPUT); + pullUpDnControl (26, PUD_UP); + + if (digitalRead(26) != HIGH) + { + printf("vB5 Present\n"); + txLed = 2; + txLedOn = HIGH; + txLedOff = LOW; + vB5 = TRUE; + onLed = 27; + onLedOn = HIGH; + onLedOff = LOW; + batteryThreshold = 3.0; + } } } + } + pinMode (txLed, OUTPUT); + digitalWrite (txLed, txLedOff); + pinMode (onLed, OUTPUT); + digitalWrite (onLed, onLedOn); + + if ((cycle == ON) && !ax5043) // don't cycle modes if using AX5043 + mode = (reset_count) % 3; // alternate between the three modes + + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", call, reset_count); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + + +if (vB4) +{ + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x44, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x45, 400); +} +else if (vB5) +{ + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-3", 0x40, 400); + sensor[MINUS_X] = config_sensor("/dev/i2c-3", 0x41, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-3", 0x44, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-3", 0x45, 400); +} +else +{ + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); + tempSensor = config_sensor("/dev/i2c-3", 0x48, 0); + } + +// try connecting to Arduino payload using UART + + if (!ax5043) // don't test if AX5043 is present + { + int uart_fd; + payload = OFF; + + if ((uart_fd = serialOpen ("/dev/ttyAMA0", 9600)) >= 0) + { + char c; + unsigned int waitTime; + int i; + for(i = 0; i < 2; i++) + { + serialPutchar (uart_fd, '?'); + printf("Querying payload with ?\n"); + waitTime = millis() + 500; + while ((millis() < waitTime) && (payload != ON)) + { + if (serialDataAvail (uart_fd)) + { + printf ("%c", c = serialGetchar (uart_fd)); + fflush (stdout); + if (c == 'O') + { + printf ("%c", c = serialGetchar (uart_fd)); + fflush (stdout); + if (c == 'K') + payload = ON; + } + } +// sleep(0.75); + } + } + if (payload == ON) + printf ("\nPayload is present!\n") ; + else + printf ("\nPayload not present!\n") ; + } + else + { + fprintf (stderr, "Unable to open UART: %s\n", strerror (errno)) ; + } + } + + int ret; + //uint8_t data[1024]; - return 0; + tx_freq_hz -= tx_channel * 50000; + +// Send ID in CW (Morse Code) + +if (cw_id == ON) // Don't send CW if using AX5043 or in mode cycling or set by 3rd argument +{ + char cw_str[200]; + char cw_header[] = "echo 'de "; + char cw_footer[] = "' > id.txt && gen_packets -M 20 id.txt -o morse.wav -r 48000 && cat morse.wav | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/rpitx/rpitx -i- -m RF -f 434.897e3"; + + strcpy(cw_str, cw_header); +//printf("Before 1st strcpy\n"); + strcat(cw_str, call); +//printf("Before 1st strcpy\n"); + strcat(cw_str, cw_footer); +//printf("Before 1st strcpy\n"); + digitalWrite (txLed, txLedOn); +//printf("Before 1st strcpy\n"); +//printf("CW String: %s\n", cw_str); + popen(cw_str,"r"); +//printf("Before 1st strcpy\n"); + sleep(6); +//printf("Before Write\n"); + digitalWrite (txLed, txLedOn); +//printf("After Write\n"); } +//printf("Done CW!\n"); + +while (loop-- != 0) + { -static void init_rf() { - int ret; - fprintf(stderr,"Initializing AX5043\n"); + float batteryVoltage = read_sensor_data(sensor[BAT]).voltage; + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Battery voltage: %f V Battery Threshold %f V\n", batteryVoltage, batteryThreshold); + #endif + if ((batteryVoltage > 0) && (batteryVoltage < batteryThreshold)) + { + fprintf(stderr,"Battery voltage too low: %f V - shutting down!\n", batteryVoltage); + popen("sudo shutdown -h now > /dev/null 2>&1", "r"); + } + + if (mode == FSK) { + bitRate = 200; + rsFrames = 1; + payloads = 1; + rsFrameLen = 64; + headerLen = 6; + dataLen = 58; + syncBits = 10; + syncWord = 0b0011111010; + parityLen = 32; + amplitude = 32767/3; + samples = S_RATE/bitRate; + bufLen = (frameCnt * (syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen))) * samples); - ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); - if (ret != PQWS_SUCCESS) { - fprintf(stderr, - "ERROR: Failed to initialize AX5043 with error code %d\n", ret); - exit(EXIT_FAILURE); + samplePeriod = ((float)((syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen))))/(float)bitRate) * 1000 - 500; + sleepTime = 0.1; + + printf("\n FSK Mode, %d bits per frame, %d bits per second, %d ms sample period\n", + bufLen/(samples * frameCnt), bitRate, samplePeriod); + } + else if (mode == BPSK) { + bitRate = 1200; + rsFrames = 3; + payloads = 6; + rsFrameLen = 159; + headerLen = 8; + dataLen = 78; + syncBits = 31; + syncWord = 0b1000111110011010010000101011101; + parityLen = 32; + amplitude = 32767; + samples = S_RATE/bitRate; + bufLen = (frameCnt * (syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen))) * samples); + +// samplePeriod = ((float)((syncBits + 10 * (headerLen + rsFrames * (rsFrameLen + parityLen))))/(float)bitRate) * 1000 - 1800; + samplePeriod = 3000; + sleepTime = 3.0; + + printf("\n BPSK Mode, bufLen: %d, %d bits per frame, %d bits per second, %d seconds per frame %d ms sample period\n", + bufLen, bufLen/(samples * frameCnt), bitRate, bufLen/(samples * frameCnt * bitRate), samplePeriod); + } + + // sleep(1); // Delay 1 second + ctr = 0; + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting TLM Data\n"); + #endif + + if (mode == AFSK) + { + get_tlm(); + } + else // FSK or BPSK + { + get_tlm_fox(); } + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting ready to send\n"); + #endif + } + + if (mode == BPSK) + { + digitalWrite (txLed, txLedOn); + printf("Sleeping to allow BPSK transmission to finish.\n"); + sleep(loop_count * 5); + printf("Done sleeping\n"); + digitalWrite (txLed, txLedOff); + } + else if (mode == FSK) + { + printf("Sleeping to allow FSK transmission to finish.\n"); + sleep(loop_count); + printf("Done sleeping\n"); + } + int transmit = popen("timeout 1 sudo /home/pi/rpitx/rpitx -i- -m RF -f 434.897e3","r"); + transmit = popen("sudo killall -9 rpitx > /dev/null 2>&1", "r"); + transmit = popen("sudo killall -9 sendiq > /dev/null 2>&1", "r"); + transmit = popen("sudo fuser -k 8080/tcp > /dev/null 2>&1", "r"); + + if(cw_id == ON) // only turn off Power LED if CW ID is enabled (i.e. not demo.sh mode cycling) + digitalWrite (onLed, onLedOff); + + return 0; } // Returns lower digit of a number which must be less than 99 @@ -292,146 +636,893 @@ int upper_digit(int number) { int digit = 0; if (number < 100) + digit = (int)(number/10); else fprintf(stderr,"ERROR: Not a digit in upper_digit!\n"); return digit; } -int get_tlm(int tlm[][5]) { + +static int init_rf() { + int ret; + fprintf(stderr,"Initializing AX5043\n"); + + ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); + if (ret != PQWS_SUCCESS) { + fprintf(stderr, + "ERROR: Failed to initialize AX5043 with error code %d\n", ret); + // exit(EXIT_FAILURE); + return(0); + } + return(1); +} + +int get_tlm(void) { + + FILE* transmit; + +for (int j = 0; j < frameCnt; j++) +{ + digitalWrite (txLed, txLedOn); + int tlm[7][5]; + memset(tlm, 0, sizeof tlm); +// Reading I2C voltage and current sensors + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING +// printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } + + tlm[1][A] = (int)(reading[BUS].voltage /15.0 + 0.5) % 100; // Current of 5V supply to Pi + tlm[1][B] = (int) (99.5 - reading[PLUS_X].current/10.0) % 100; // +X current [4] + tlm[1][C] = (int) (99.5 - reading[MINUS_X].current/10.0) % 100; // X- current [10] + tlm[1][D] = (int) (99.5 - reading[PLUS_Y].current/10.0) % 100; // +Y current [7] -// Reading I2C voltage and current sensors + tlm[2][A] = (int) (99.5 - reading[MINUS_Y].current/10.0) % 100; // -Y current [10] + tlm[2][B] = (int) (99.5 - reading[PLUS_Z].current/10.0) % 100; // +Z current [10] // was 70/2m transponder power, AO-7 didn't have a Z panel + tlm[2][C] = (int) (99.5 - reading[MINUS_Z].current/10.0) % 100; // -Z current (was timestamp) + tlm[2][D] = (int)(50.5 + reading[BAT].current/10.0) % 100; // NiMH Battery current - char cmdbuffer[1000]; - FILE* file = popen("sudo python /home/pi/CubeSatSim/python/readcurrent.py 2>&1", "r"); - fgets(cmdbuffer, 999, file); - pclose(file); - fprintf(stderr,"I2C Sensor data: %s\n", cmdbuffer); - - char ina219[16][20]; // voltage, currents, and power from the INA219 current sensors x4a, x40, x41, x44, and x45. - int i = 0; - char * data2 = strtok (cmdbuffer," "); - - while (data2 != NULL) { - strcpy(ina219[i], data2); - // printf ("ina219[%d]=%s\n",i,ina219[i]); - data2 = strtok (NULL, " "); - i++; + tlm[3][A] = abs((int)((reading[BAT].voltage * 10.0) - 65.5) % 100); + tlm[3][B] = (int)(reading[BUS].voltage * 10.0) % 100; // 5V supply to Pi + + if (ax5043) + { + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + tlm[4][A] = (int)((95.8 - temp)/1.48 + 0.5) % 100; + } + } + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + tlm[4][B] = (int)((95.8 - cpuTemp)/1.48 + 0.5) % 100; + fclose (cpuTempSensor); + } + + tlm[6][B] = 0 ; + tlm[6][D] = 49 + rand() % 3; + + #ifdef DEBUG_LOGGING +// Display tlm + int k, j; + for (k = 1; k < 7; k++) { + for (j = 1; j < 5; j++) { + printf(" %2d ", tlm[k][j]); } + printf("\n"); + } + #endif + + char str[1000]; + char tlm_str[1000]; + char header_str[] = "\x03\xf0hi hi "; + char header_str3[] = "echo '"; + char header_str2[] = ">CQ:hi hi "; + char footer_str1[] = "\' > t.txt && echo \'"; + char footer_str[] = ">CQ:hi hi ' >> t.txt && gen_packets -o telem.wav t.txt -r 48000 > /dev/null 2>&1 && cat telem.wav | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/rpitx/rpitx -i- -m RF -f 434.897e3 > /dev/null 2>&1"; + + if (ax5043) + { + strcpy(str, header_str); + } + else + { + strcpy(str, header_str3); + strcat(str, call); + strcat(str, header_str2); + } + + int channel; + for (channel = 1; channel < 7; channel++) { + sprintf(tlm_str, "%d%d%d %d%d%d %d%d%d %d%d%d ", + channel, upper_digit(tlm[channel][1]), lower_digit(tlm[channel][1]), + channel, upper_digit(tlm[channel][2]), lower_digit(tlm[channel][2]), + channel, upper_digit(tlm[channel][3]), lower_digit(tlm[channel][3]), + channel, upper_digit(tlm[channel][4]), lower_digit(tlm[channel][4])); +// printf("%s",tlm_str); + strcat(str, tlm_str); + } + + if (ax5043) + { + digitalWrite (txLed, txLedOn); + fprintf(stderr,"INFO: Transmitting X.25 packet\n"); + memcpy(data, str, strnlen(str, 256)); + int ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } + ax5043_wait_for_transmit(); + digitalWrite (txLed, txLedOff); + + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } + sleep(2); + } + else + { + strcat(str, footer_str1); + strcat(str, call); + strcat(str,footer_str); + fprintf(stderr, "String to execute: %s\n", str); + FILE* file2 = popen(str, "r"); + pclose(file2); + digitalWrite (txLed, txLedOff); + sleep(3); + digitalWrite (txLed, txLedOn); + } + + //digitalWrite (txLed, txLedOff); + + } + +printf("End of get_tlm and rpitx =========================================================\n"); + + digitalWrite (txLed, txLedOff); + +return; +} + +int get_tlm_fox() { + +// memset(b, 0, 64); + +// Reading I2C voltage and current sensors + + FILE* uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + #ifdef DEBUG_LOGGING + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + #endif + fclose(uptime_file); + + int i; +// long int sync = SYNC_WORD; + long int sync = syncWord; + + smaller = S_RATE/(2 * freq_Hz); + +// short int b[DATA_LEN]; + short int b[dataLen]; + memset(b, 0, sizeof(b)); + +// short int h[HEADER_LEN]; + short int h[headerLen]; + memset(h, 0, sizeof(h)); + + memset(buffer, 0xa5, sizeof(buffer)); - // Reading MoPower telemetry info -/* - file = popen("/home/pi/mopower/mpcmd show data", "r"); +// short int b10[DATA_LEN], h10[HEADER_LEN]; +// short int rs_frame[RS_FRAMES][223]; +// unsigned char parities[RS_FRAMES][PARITY_LEN],inputByte; +// short int b10[dataLen], h10[headerLen]; + short int rs_frame[rsFrames][223]; + unsigned char parities[rsFrames][parityLen], inputByte; - fgets(cmdbuffer, 999, file); + int id, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0, STEMBoardFailure = 16; + int PSUVoltage = 0, PSUCurrent = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 0, battCurr = 0; + int posXv = 0, negXv = 0, posYv = 0, negYv = 0, posZv = 0, negZv = 0; + int posXi = 0, negXi = 0, posYi = 0, negYi = 0, posZi = 0, negZi = 0; + int head_offset = 0; + + short int buffer_test[bufLen]; + int buffSize; + buffSize = sizeof(buffer_test); + + if (mode == FSK) + id = 7; + else + id = 0; // 99 in h[6] - pclose(file); -// printf("MoPower data: %s\n", cmdbuffer); +// for (int frames = 0; frames < FRAME_CNT; frames++) + for (int frames = 0; frames < frameCnt; frames++) + { - char mopower[64][14]; -// char str[] ="- This, a sample string."; - char * pch; -// printf ("Splitting string \"%s\" into tokens:\n",str); -// pch = strtok (str," "); - i = 0; - pch = strtok (cmdbuffer," ,.-"); - while (pch != NULL) +if (firstTime != ON) +/* +{// digitalWrite (3, HIGH); + if (mode == BPSK) + sleep(3); + // sleep(3.5); +// digitalWrite (3, LOW); +} + + if (mode == FSK) +*/ + { +// delay for sample period + digitalWrite (txLed, txLedOn); + + while ((millis() - sampleTime) < samplePeriod) + sleep(sleepTime); + + digitalWrite (txLed, txLedOff); + + printf("Sample period: %d\n",millis() - sampleTime); + sampleTime = millis(); + } else + printf("first time - no sleep\n"); + + int count; + for (count = 0; count < 8; count++) { - strcpy(mopower[i], pch); -// printf ("mopwer[%d]=%s\n",i,mopower[i]); // pch); - pch = strtok (NULL, " "); - i++; + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING +// printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// count, reading[count].voltage, reading[count].current, reading[count].power); + #endif } - printf("Battery voltage = %s\n", mopower[16]); - if (strtof(mopower[17],NULL) > -0.5) { - charging = 1; - printf("Charging on\n"); - } - else { - charging = 0; - printf("Charging off\n"); +/* + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif - } -*/ -// read i2c current sensors // - double current = 0, power = 0, y_current = 0, y_power = 0, z_current = 0, z_power = 0; - if (x_fd != -1) { - wiringPiI2CWriteReg16(x_fd, INA219_REG_CALIBRATION, x_calValue_x); - wiringPiI2CWriteReg16(x_fd, INA219_REG_CONFIG, config); - wiringPiI2CWriteReg16(x_fd, INA219_REG_CALIBRATION, x_calValue_x); - current = wiringPiI2CReadReg16(x_fd, INA219_REG_CURRENT) / x_currentDivider; - power = wiringPiI2CReadReg16(x_fd, INA219_REG_POWER) * x_powerMultiplier; - wiringPiI2CWriteReg16(y_fd, INA219_REG_CALIBRATION, x_calValue_x); - wiringPiI2CWriteReg16(y_fd, INA219_REG_CONFIG, config); - wiringPiI2CWriteReg16(y_fd, INA219_REG_CALIBRATION, x_calValue_x); - y_current = wiringPiI2CReadReg16(y_fd, INA219_REG_CURRENT) / x_currentDivider; - y_power = wiringPiI2CReadReg16(y_fd, INA219_REG_POWER) * x_powerMultiplier; - wiringPiI2CWriteReg16(z_fd, INA219_REG_CALIBRATION, x_calValue_x); - wiringPiI2CWriteReg16(z_fd, INA219_REG_CONFIG, config); - wiringPiI2CWriteReg16(z_fd, INA219_REG_CALIBRATION, x_calValue_x); - z_current = wiringPiI2CReadReg16(z_fd, INA219_REG_CURRENT) / x_currentDivider; - z_power = wiringPiI2CReadReg16(z_fd, INA219_REG_POWER) * x_powerMultiplier; - } - printf("-X 0x40 current %4.2f power %4.2f -Y 0x41 current %4.2f power %4.2f -Z 0x44 current %4.2f power %4.2f \n", - current, power, y_current, y_power, z_current, z_power); - -// printf("1B: ina219[%d]: %s val: %f \n", SENSOR_40 + CURRENT, ina219[SENSOR_40 + CURRENT], strtof(ina219[SENSOR_40 + CURRENT], NULL)); - - tlm[1][A] = (int)(strtof(ina219[SENSOR_4A + CURRENT], NULL) / 15 + 0.5) % 100; // Current of 5V supply to Pi - tlm[1][B] = (int) (99.5 - strtof(ina219[SENSOR_40 + CURRENT], NULL)/10) % 100; // +X current [4] - tlm[1][C] = (int) (99.5 - current/10) % 100; // X- current [10] - tlm[1][D] = (int) (99.5 - strtof(ina219[SENSOR_41 + CURRENT], NULL)/10) % 100; // +Y current [7] - - tlm[2][A] = (int) (99.5 - y_current/10) % 100; // -Y current [10] - tlm[2][B] = (int) (99.5 - strtof(ina219[SENSOR_44 + CURRENT], NULL)/10) % 100; // +Z current [10] // was 70/2m transponder power, AO-7 didn't have a Z panel - tlm[2][C] = (int) (99.5 - z_current/10) % 100; // -Z current (was timestamp) - -// tlm[2][C] = (int)((time(NULL) - timestamp) / 15) % 100; - tlm[2][D] = (int)(50.5 + strtof(ina219[SENSOR_45 + CURRENT], NULL)/10.0) % 100; // NiMH Battery current - - tlm[3][A] = abs((int)((strtof(ina219[SENSOR_45 + VOLTAGE], NULL) * 10) - 65.5) % 100); - tlm[3][B] = (int)(strtof(ina219[SENSOR_4A + VOLTAGE], NULL) * 10.0) % 100; // 5V supply to Pi - - if (tempSensor != -1) { - int tempValue = wiringPiI2CReadReg16(tempSensor, 0); -// printf("Read: %x\n", tempValue); - uint8_t upper = (uint8_t) (tempValue >> 8); - uint8_t lower = (uint8_t) (tempValue & 0xff); - float temp = (float)lower + ((float)upper / 0x100); - - tlm[4][A] = (int)((95.8 - temp)/1.48 + 0.5) % 100; - } - FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); - if (cpuTempSensor) { + TxTemp = (int)((temp * 10.0) + 0.5); + encodeB(b, 34 + head_offset, TxTemp); + } +*/ + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { double cpuTemp; fscanf (cpuTempSensor, "%lf", &cpuTemp); cpuTemp /= 1000; - printf("CPU Temp Read: %6.1f\n", cpuTemp); - tlm[4][B] = (int)((95.8 - cpuTemp)/1.48 + 0.5) % 100; - fclose (cpuTempSensor); + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + IHUcpuTemp = (int)((cpuTemp * 10.0) + 0.5); + } + + memset(rs_frame,0,sizeof(rs_frame)); + memset(parities,0,sizeof(parities)); + + FILE *uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + fclose(uptime_file); + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + + h[0] = (h[0] & 0xf8) | (id & 0x07); // 3 bits +// printf("h[0] %x\n", h[0]); + h[0] = (h[0] & 0x07)| ((reset_count & 0x1f) << 3); +// printf("h[0] %x\n", h[0]); + h[1] = (reset_count >> 5) & 0xff; +// printf("h[1] %x\n", h[1]); + h[2] = (h[2] & 0xf8) | ((reset_count >> 13) & 0x07); +// printf("h[2] %x\n", h[2]); + h[2] = (h[2] & 0x0e) | ((uptime & 0x1f) << 3); +// printf("h[2] %x\n", h[2]); + h[3] = (uptime >> 5) & 0xff; + h[4] = (uptime >> 13) & 0xff; + h[5] = (h[5] & 0xf0) | ((uptime >> 21) & 0x0f); + h[5] = (h[5] & 0x0f) | (frm_type << 4); + + if (mode == BPSK) + h[6] = 99; + +// posXv = reading[PLUS_X].current; + posXi = (int)reading[PLUS_X].current + 2048; + posYi = (int)reading[PLUS_Y].current + 2048; + posZi = (int)reading[PLUS_Z].current + 2048; + negXi = (int)reading[MINUS_X].current + 2048; + negYi = (int)reading[MINUS_Y].current + 2048; + negZi = (int)reading[MINUS_Z].current + 2048; + + posXv = (int)(reading[PLUS_X].voltage * 100); + posYv = (int)(reading[PLUS_Y].voltage* 100); + posZv = (int)(reading[PLUS_Z].voltage * 100); + negXv = (int)(reading[MINUS_X].voltage * 100); + negYv = (int)(reading[MINUS_Y].voltage * 100); + negZv = (int)(reading[MINUS_Z].voltage * 100); + + batt_c_v = (int)(reading[BAT].voltage * 100); + battCurr = (int)reading[BAT].current + 2048; + PSUVoltage = (int)reading[BUS].voltage * 100; + PSUCurrent = (int)reading[BUS].current + 2048; + + if (payload == ON) + STEMBoardFailure = 0; + +/* + posXv = 10, negXv = 20, posYv = 30, negYv = 40, posZv = 50, negZv = 60; + posXi = 110, negXi = 120, posYi = 130, negYi = 140, posZi = 150, negZi = 160; +*/ + encodeA(b, 0 + head_offset, batt_a_v); + encodeB(b, 1 + head_offset, batt_b_v); + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); + + encodeA(b, 12 + head_offset,posXv); + encodeB(b, 13 + head_offset,negXv); + encodeA(b, 15 + head_offset,posYv); + encodeB(b, 16 + head_offset,negYv); + encodeA(b, 18 + head_offset,posZv); + encodeB(b, 19 + head_offset,negZv); + + encodeA(b, 21 + head_offset,posXi); + encodeB(b, 22 + head_offset,negXi); + encodeA(b, 24 + head_offset,posYi); + encodeB(b, 25 + head_offset,negYi); + encodeA(b, 27 + head_offset,posZi); + encodeB(b, 28 + head_offset,negZi); + + encodeA(b, 30 + head_offset,PSUVoltage); + encodeB(b, 46 + head_offset,PSUCurrent); + + encodeA(b, 39 + head_offset, IHUcpuTemp); + + encodeB(b, 51 + head_offset, STEMBoardFailure); + + +/* batt_c_v += 10; + battCurr -= 10; + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); +*/ + short int data10[headerLen + rsFrames * (rsFrameLen + parityLen)]; + short int data8[headerLen + rsFrames * (rsFrameLen + parityLen)]; + + int ctr1 = 0; + int ctr3 = 0; +// for (i = 0; i < RS_FRAME_LEN; i++) + for (i = 0; i < rsFrameLen; i++) + { +// for (int j = 0; j < RS_FRAMES ; j++) + for (int j = 0; j < rsFrames ; j++) + { +// if (!((i == (RS_FRAME_LEN - 1)) && (j == 2))) // skip last one for BPSK + if (!((i == (rsFrameLen - 1)) && (j == 2))) // skip last one for BPSK + { +// if (ctr1 < HEADER_LEN) + if (ctr1 < headerLen) + { + rs_frame[j][i] = h[ctr1]; + update_rs(parities[j], h[ctr1]); + // printf("header %d rs_frame[%d][%d] = %x \n", ctr1, j, i, h[ctr1]); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + } + else + { +// rs_frame[j][i] = b[ctr3 % DATA_LEN]; + rs_frame[j][i] = b[ctr3 % dataLen]; +// update_rs(parities[j], b[ctr3 % DATA_LEN]); + update_rs(parities[j], b[ctr3 % dataLen]); + // printf("%d rs_frame[%d][%d] = %x %d \n", + // ctr1, j, i, b[ctr3 % DATA_LEN], ctr3 % DATA_LEN); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + ctr3++; + } + } + } + } + + #ifdef DEBUG_LOGGING +// printf("\nAt end of data8 write, %d ctr1 values written\n\n", ctr1); + + printf("Parities "); +// for (int m = 0; m < PARITY_LEN; m++) { + for (int m = 0; m < parityLen; m++) { + printf("%d ", parities[0][m]); + } + printf("\n"); + #endif + + int ctr2 = 0; + memset(data10,0,sizeof(data10)); + + +// for (i = 0; i < DATA_LEN * PAYLOADS + HEADER_LEN; i++) // 476 for BPSK + for (i = 0; i < dataLen * payloads + headerLen; i++) // 476 for BPSK + { + data10[ctr2] = (Encode_8b10b[rd][((int)data8[ctr2])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)data8[ctr2])] >> 10) & 1; + // printf ("data10[%d] = encoded data8[%d] = %x \n", + // ctr2, ctr2, data10[ctr2]); + + rd = nrd; // ^ nrd; + ctr2++; + } +// for (i = 0; i < PARITY_LEN; i++) + for (i = 0; i < parityLen; i++) + { +// for (int j = 0; j < RS_FRAMES; j++) + for (int j = 0; j < rsFrames; j++) + { + data10[ctr2++] = (Encode_8b10b[rd][((int)parities[j][i])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)parities[j][i])] >> 10) & 1; + // printf ("data10[%d] = encoded parities[%d][%d] = %x \n", + // ctr2 - 1, j, i, data10[ctr2 - 1]); + + rd = nrd; + } + } + #ifdef DEBUG_LOGGING +// printf("\nAt end of data10 write, %d ctr2 values written\n\n", ctr2); + #endif + + int data; + int val; + int offset = 0; + + #ifdef DEBUG_LOGGING +// printf("\nAt start of buffer loop, syncBits %d samples %d ctr %d\n", syncBits, samples, ctr); + #endif + +// for (i = 1; i <= SYNC_BITS * SAMPLES; i++) + for (i = 1; i <= syncBits * samples; i++) + { + write_wave(ctr, buffer); +// printf("%d ",ctr); +// if ( (i % SAMPLES) == 0) { + if ( (i % samples) == 0) { +// int bit = SYNC_BITS - i/SAMPLES + 1; + int bit = syncBits - i/samples + 1; + val = sync; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d sync bit %d = %d \n", + // ctr/SAMPLES, i, frames, bit, (data > 0) ); + if (mode == FSK) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + #ifdef DEBUG_LOGGING +// printf("\n\nValue of ctr after header: %d Buffer Len: %d\n\n", ctr, buffSize); + #endif + for (i = 1; +// i <= (10 * (HEADER_LEN + DATA_LEN * PAYLOADS + RS_FRAMES * PARITY_LEN) * SAMPLES); i++) // 572 + i <= (10 * (headerLen + dataLen * payloads + rsFrames * parityLen) * samples); i++) // 572 + { + write_wave(ctr, buffer); +// if ( (i % SAMPLES) == 0) { + if ( (i % samples) == 0) { +// int symbol = (int)((i - 1)/ (SAMPLES * 10)); +// int bit = 10 - (i - symbol * SAMPLES * 10) / SAMPLES + 1; + int symbol = (int)((i - 1)/ (samples * 10)); + int bit = 10 - (i - symbol * samples * 10) / samples + 1; + val = data10[symbol]; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d data10[%d] = %x bit %d = %d \n", + // ctr/SAMPLES, i, frames, symbol, val, bit, (data > 0) ); + if (mode == FSK) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j ++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } } + #ifdef DEBUG_LOGGING +// printf("\nValue of ctr after looping: %d Buffer Len: %d\n", ctr, buffSize); +// printf("\ctr/samples = %d ctr/(samples*10) = %d\n\n", ctr/samples, ctr/(samples*10)); + #endif + + int error = 0; + int count; +// for (count = 0; count < DATA_LEN; count++) { +// for (count = 0; count < dataLen; count++) { +// printf("%02X", b[count]); +// } +// printf("\n"); + +// rpitx + + char cmdbuffer[1000]; + FILE* transmit; + if ((rpitxStatus != mode)) // || (mode == BPSK)) + { // change rpitx mode + rpitxStatus = mode; + printf("Changing rpitx mode!\n"); +// transmit = popen("ps -ef | grep rpitx | grep -v grep | awk '{print $2}' | sudo xargs kill -9 > /dev/null 2>&1", "r"); + transmit = popen("sudo killall -9 rpitx > /dev/null 2>&1", "r"); +// printf("1\n"); +// sleep(1); +// transmit = popen("ps -ef | grep sendiq | grep -v grep | awk '{print $2}' | sudo xargs kill -9 > /dev/null 2>&1", "r"); + transmit = popen("sudo killall -9 sendiq > /dev/null 2>&1", "r"); +// printf("2\n"); +// digitalWrite (txLed, txLedOn); + sleep(1); + transmit = popen("sudo fuser -k 8080/tcp > /dev/null 2>&1", "r"); + socket_open = 0; + +// printf("3\n"); + sleep(1); +// digitalWrite (txLed, txLedOff); + + if (mode == FSK) { + // transmit = popen("sudo nc -l 8080 | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/rpitx/rpitx -i- -m RF -f 434.896e3&", "r"); + transmit = popen("sudo nc -l 8080 | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/rpitx/rpitx -i- -m RF -f 434.897e3&", "r"); +// printf("4\n"); + } else if (mode == BPSK) { +// transmit = popen("sudo nc -l 8080 | csdr convert_i16_f | csdr fir_interpolate_cc 2 | csdr dsb_fc | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff | sudo /home/pi/CubeSatSim/rpitx/sendiq -i /dev/stdin -s 96000 -f 434.8925e6 -t float 2>&1&", "r"); + transmit = popen("sudo nc -l 8080 | csdr convert_i16_f | csdr fir_interpolate_cc 2 | csdr dsb_fc | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff | sudo /home/pi/rpitx/sendiq -i /dev/stdin -s 96000 -f 434.8945e6 -t float 2>&1&", "r"); + } +// fgets(cmdbuffer, 1000, transmit); + pclose(transmit); + sleep(2); +// printf("Results of transmit command: %s\n", cmdbuffer); + } + +// socket write + + if (!socket_open) + { + printf("Opening socket!\n"); + struct sockaddr_in address; + int valread; + struct sockaddr_in serv_addr; +// char *hello = "Hello from client"; +// char buffer[1024] = {0}; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + printf("\n Socket creation error \n"); + error = 1; + } + + memset(&serv_addr, '0', sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + // Convert IPv4 and IPv6 addresses from text to binary form + if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) + { + printf("\nInvalid address/ Address not supported \n"); + error = 1; + } + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + printf("\nConnection Failed \n"); + printf("Error: %s \n", strerror(errno)); + error = 1; + } + if (error == 1) + ; //rpitxStatus = -1; + else + socket_open = 1; + } + + if (!error) + { +// digitalWrite (0, LOW); + printf("Sending %d buffer bytes over socket after %d ms!\n", ctr, millis()-start); + start = millis(); +// int sock_ret = send(sock, buffer, buffSize, 0); + int sock_ret = send(sock, buffer, ctr * 2 + 2, 0); + printf("Millis5: %d Result of socket send: %d \n", millis() - start, sock_ret); + + if (sock_ret < (ctr * 2 + 2)) + { + printf("Resending\n"); +// sock_ret = send(sock, buffer[sock_ret], ctr * 2 + 2 - sock_ret, 0); + printf("Millis10: %d Result of socket send: %d \n", millis() - start, sock_ret); + } + + if (sock_ret == -1) { + printf("Error: %s \n", strerror(errno)); + socket_open = 0; + //rpitxStatus = -1; + } + } +// digitalWrite (0, HIGH); + firstTime = 0; + +return 0; +} + + /* + * TelemEncoding.h + * + * Created on: Feb 3, 2014 + * Author: fox + */ + +#include +#include +#include +#include +#include +#include + +#define false 0 +#define true 1 + +//static int twosToInt(int val,int len); +//static int encodeB(short int *b, int index, int val); +//static int encodeA(short int *b, int index, int val); + + static int NOT_FRAME = /* 0fa */ 0xfa & 0x3ff; + static int FRAME = /* 0fa */ ~0xfa & 0x3ff; + /* -FILE *temperatureFile; -double T; -temperatureFile = fopen ("/sys/class/thermal/thermal_zone0/temp", "r"); -if (temperatureFile == NULL) - ; //print some message -fscanf (temperatureFile, "%lf", &T); -T /= 1000; -printf ("The temperature is %6.3f C.\n", T); -fclose (temperatureFile); -tlm[4][B] = (int)((95.8 - T)/1.48 + 0.5) % 100; + * TelemEncoding.c + * + Fox-1 telemetry encoder + January 2014 Phil Karn KA9Q + + This file has two external functions: + void update_rs(unsigned char parity[32],unsigned char data); + int encode_8b10b(int *state,int data). + + update_rs() is the Reed-Solomon encoder. Its first argument is the 32-byte + encoder shift register, the second is the 8-bit data byte being encoded. It updates + the shift register in place and returns void. At the end of each frame, it contains + the parities ready for transmission, starting with parity[0]. + Be sure to zero this array before each new frame! + + encode_8b10b() is the 8b10b encoder. Its first argument is a pointer to a single integer + with the 1-bit encoder state (the current run disparity, or RD). Initialize it to 0 + JUST ONCE at startup (not between frames). + The second argument is the data byte being encoded. It updates the state and returns + an integer containing the 10-bit encoded word, right justified. + Transmit this word from left to right. + + The data argument is an int so it can hold the special value -1 to indicate end of frame; + it generates the 8b10b control word K.28.5, which is used as an inter-frame flag. + + Some assert() calls are made to verify legality of arguments. These can be turned off in + production code. + + + sample frame transmission code: + + unsigned char data[64]; // Data block to be sent + unsigned char parity[32]; // RS parities + void transmit_word(int); // User provided transmit function: 10 bits of data in bits 9....0 + int state,i; + + state = 0; // Only once at startup, not between frames + memset(parity,0,sizeof(parity); // Do this before every frame + // Transmit the data, updating the RS encoder + for(i=0;i<64;i++){ + update_rs(parity,data[i]); + transmit_word(encode_8b10b(&state,data[i]); + } + // Transmit the RS parities + for(i=0;i<32;i++) + transmit_word(encode_8b10b(&state,parity[i]); + + transmit_word(encode_8b10b(&state,-1); // Transmit end-of-frame flag */ - tlm[6][B] = 0 ; - tlm[6][D] = 49 + rand() % 3; -// Display tlm - int k, j; - for (k = 1; k < 7; k++) { - for (j = 1; j < 5; j++) { - printf(" %2d ", tlm[k][j]); + +#include +//#include "Fox.h" +//#include "TelemEncoding.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define NN (0xff) // Frame size in symbols +#define A0 (NN) // special value for log(0) + + +// GF Antilog lookup table table +static unsigned char CCSDS_alpha_to[NN+1] = { +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, +0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, +0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, +0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, +0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, +0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, +0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, +0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, +0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, +0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, +0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, +0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, +0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, +0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, +0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, +0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, +}; + +// GF log lookup table. Special value represents log(0) +static unsigned char CCSDS_index_of[NN+1] = { + A0, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, + 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, + 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, +103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, + 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, +202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, +104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, +110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, + 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, +209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, +203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, +192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, +105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, +130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, +111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, + 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, +}; + +// Only half the coefficients are given here because the +// generator polynomial is palindromic; G0 = G32, G1 = G31, etc. +// Only G16 is unique +static unsigned char CCSDS_poly[] = { + 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, + 24, +}; + +static inline int modnn(int x){ + while (x >= NN) { + x -= NN; + x = (x >> 8) + (x & NN); + } + return x; +} + +// Update Reed-Solomon encoder +// parity -> 32-byte reed-solomon encoder state; clear this to zero before each frame +void update_rs( + unsigned char parity[32], // 32-byte encoder state; zero before each frame + unsigned char c) // Current data byte to update +{ + unsigned char feedback; + int j,t; + + assert(parity != NULL); + feedback = CCSDS_index_of[c ^ parity[0]]; + if(feedback != A0){ // only if feedback is non-zero + // Take advantage of palindromic polynomial to halve the multiplies + // Do G1...G15, which is the same as G17...G31 + for(j=1;j0) + { buf = word & 0xff; + fwrite(&buf, 1,1, wav_file); + num_bytes--; + word >>= 8; } - printf("\n"); - } - return 0; +} + + +void write_wave(int i, short int *buffer) +{ + if (mode == FSK) + { + if ((ctr - flip_ctr) < smaller) + buffer[ctr++] = 0.1 * phase * (ctr - flip_ctr) / smaller; + else + buffer[ctr++] = 0.25 * amplitude * phase; + } + else + { + if ((ctr - flip_ctr) < smaller) + buffer[ctr++] = (int)(amplitude * 0.4 * phase * sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + else + buffer[ctr++] = (int)(amplitude * phase * sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + } +// printf("%d %d \n", i, buffer[ctr - 1]); + +} + +int encodeA(short int *b, int index, int val) { +// printf("Encoding A\n"); + b[index] = val & 0xff; + b[index + 1] = (b[index + 1] & 0xf0) | ((val >> 8) & 0x0f); + return 0; +} + +int encodeB(short int *b, int index, int val) { +// printf("Encoding B\n"); + b[index] = (b[index] & 0x0f) | ((val << 4) & 0xf0); + b[index + 1] = (val >> 4 ) & 0xff; + return 0; +} + +int twosToInt(int val,int len) { // Convert twos compliment to integer +// from https://www.raspberrypi.org/forums/viewtopic.php?t=55815 + + if(val & (1 << (len - 1))) + val = val - (1 << len); + + return(val); } diff --git a/afsk/main.c.x25_only b/afsk/main.c.x25_only deleted file mode 100644 index 7a67a49c..00000000 --- a/afsk/main.c.x25_only +++ /dev/null @@ -1,85 +0,0 @@ -/* - * A sample application transmitting AFSK at 1200 baud - * - * Portions Copyright (C) 2018 Jonathan Brandenburg - * - * 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 "status.h" -#include "ax5043.h" -#include "ax25.h" -#include "spi/ax5043spi.h" - -ax5043_conf_t hax5043; -ax25_conf_t hax25; - -static void init_rf(); - -int main(void) { - setSpiChannel(SPI_CHANNEL); - setSpiSpeed(SPI_SPEED); - initializeSpi(); - - init_rf(); - - ax25_init(&hax25, (uint8_t *) "CQ", '2', (uint8_t *) "DX", '2', - AX25_PREAMBLE_LEN, - AX25_POSTAMBLE_LEN); - - int ret; - uint8_t data[1024]; - // 0x03 is a UI frame - // 0x0F is no Level 3 protocol - const char *str = "\x03\x0fThis is an AX.25 Packet from CubeSatSim!!!"; - - /* Infinite loop */ - for (;;) { - sleep(2); - printf("INFO: Transmitting a packet\n"); - - memcpy(data, str, strnlen(str, 256)); - ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); - if (ret) { - fprintf(stderr, - "ERROR: Failed to transmit AX.25 frame with error code %d\n", - ret); - exit(EXIT_FAILURE); - } - ax5043_wait_for_transmit(); - if (ret) { - fprintf(stderr, - "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", - ret); - exit(EXIT_FAILURE); - } - - } - - return 0; -} - -static void init_rf() { - int ret; - ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); - if (ret != PQWS_SUCCESS) { - fprintf(stderr, - "ERROR: Failed to initialize AX5043 with error code %d\n", ret); - exit(EXIT_FAILURE); - } -} diff --git a/afsk/main2.c b/afsk/main2.c new file mode 100644 index 00000000..96083285 --- /dev/null +++ b/afsk/main2.c @@ -0,0 +1,1137 @@ +/* + * Transmits CubeSat Telemetry at 434.9MHz in AO-7 format + * + * Copyright Alan B. Johnston + * + * Portions Copyright (C) 2018 Jonathan Brandenburg + * + * 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 . + * + * INA219 Raspberry Pi wiringPi code is based on Adafruit Arduino wire code + * from https://github.com/adafruit/Adafruit_INA219. + */ + +#include +#include +#include +#include +#include +#include "status.h" +#include "ax5043.h" +#include "ax25.h" +#include "spi/ax5043spi.h" +#include +#include +#include +#include +#include "Adafruit_INA219.h" // From Adafruit INA219 library for Arduino +#include "make_wav.h" + +#define A 1 +#define B 2 +#define C 3 +#define D 4 + +#define PLUS_X 0 +#define PLUS_Y 1 +#define PLUS_Z 2 +#define BAT 3 +#define MINUS_X 4 +#define MINUS_Y 5 +#define MINUS_Z 6 +#define BUS 7 +#define OFF -1 + +uint32_t tx_freq_hz = 434900000 + FREQUENCY_OFFSET; +uint32_t tx_channel = 0; + +ax5043_conf_t hax5043; +ax25_conf_t hax25; + +static void init_rf(); +int twosToInt(int val, int len); +int get_tlm(char *str); +int get_tlm_fox(); +int encodeA(short int *b, int index, int val); +int encodeB(short int *b, int index, int val); +void config_x25(); +void trans_x25(); +int upper_digit(int number); +int lower_digit(int number); + +#define S_RATE (48000) // (44100) +#define BUF_SIZE (S_RATE*10) /* 2 second buffer */ + +// BPSK Settings +#define BIT_RATE 1200 // 200 for DUV +#define DUV 0 // 1 for DUV +#define RS_FRAMES 3 // 3 frames for BPSK, 1 for DUV +#define PAYLOADS 6 // 1 for DUV +#define DATA_LEN 78 // 56 for DUV +#define RS_FRAME_LEN 159 // 64 for DUV +#define SYNC_BITS 31 // 10 for DUV +#define SYNC_WORD 0b1000111110011010010000101011101 // 0b0011111010 for DUV +#define HEADER_LEN 8 // 6 for DUV +/* +// DUV Settings +#define BIT_RATE 200 +#define DUV 1 +#define RS_FRAMES 1 +#define PAYLOADS 1 +#define RS_FRAME_LEN 64 +#define HEADER_LEN 6 +#define DATA_LEN 58 +#define SYNC_BITS 10 +#define SYNC_WORD 0b0011111010 +*/ + +#define PARITY_LEN 32 + +float amplitude = 32767/3; // 20000; // 32767/(10%amp+5%amp+100%amp) +float freq_Hz = 3000; // 1200 + +int smaller; +int flip_ctr = 0; +int phase = 1; +int ctr = 0; +void write_to_buffer(int i, int symbol, int val); +void write_wave(); +#define SAMPLES (S_RATE / BIT_RATE) +#define FRAME_CNT 33 // Add 3 frames to the count + +//#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (8 + 6 * DATA_LEN + 96)) * SAMPLES) +#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN))) * SAMPLES) +short int buffer[BUF_LEN]; +short int data10[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +short int data8[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +int reset_count; +float uptime_sec; +long int uptime; +char call[5]; + +struct SensorConfig { + int fd; + uint16_t config; + int calValue; + int powerMultiplier; + int currentDivider; +}; + +struct SensorData { + double current; + double voltage; + double power; +}; + +/** + * @brief Read the data from one of the i2c current sensors. + * + * Reads the current data from the requested i2c current sensor configuration and + * stores it into a SensorData struct. An invalid file descriptor (i.e. less than zero) + * results in a SensorData struct being returned that has both its #current and #power members + * set to NAN. + * + * @param sensor A structure containing sensor configuration including the file descriptor. + * @return struct SensorData A struct that contains the current, voltage, and power readings + * from the requested sensor. + */ +struct SensorData read_sensor_data(struct SensorConfig sensor) { + struct SensorData data = { + .current = NAN, + .voltage = NAN, + .power = NAN }; + + if (sensor.fd < 0) { + return data; + } + // doesn't read negative currents accurately, shows -0.1mA + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CONFIG, sensor.config); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + int value = wiringPiI2CReadReg16(sensor.fd, INA219_REG_CURRENT); + data.current = (float) twosToInt(value, 16) / (float) sensor.currentDivider; + + wiringPiI2CWrite(sensor.fd, INA219_REG_BUSVOLTAGE); + delay(1); // Max 12-bit conversion time is 586us per sample + value = (wiringPiI2CRead(sensor.fd) << 8 ) | wiringPiI2CRead (sensor.fd); + data.voltage = ((float)(value >> 3) * 4) / 1000; + // power has very low resolution, seems to step in 512mW values + data.power = (float) wiringPiI2CReadReg16(sensor.fd, INA219_REG_POWER) * (float) sensor.powerMultiplier; + + return data; +} + +/** + * @brief Configures an i2c current sensor. + * + * Calculates the configuration values of the i2c sensor so that + * current, voltage, and power can be read using read_sensor_data. + * Supports 16V 400mA and 16V 2.0A settings. + * + * @param sensor A file descriptor that can be used to read from the sensor. + * @param milliAmps The mA configuration, either 400mA or 2A are supported. + * @return struct SensorConfig A struct that contains the configuraton of the sensor. + */ +//struct SensorConfig config_sensor(int sensor, int milliAmps) { +struct SensorConfig config_sensor(char *bus, int address, int milliAmps) { + struct SensorConfig data; + + if (access(bus, W_OK | R_OK) < 0) { // Test if I2C Bus is missing + printf("ERROR: %s bus not present \n", bus); + data.fd = OFF; + return (data); + } + + data.fd = wiringPiI2CSetupInterface(bus, address); + + data.config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_1_40MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_1S_532US | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + if (milliAmps == 400) { // INA219 16V 400mA configuration + data.calValue = 8192; + data.powerMultiplier = 1; + data.currentDivider = 20; // 40; in Adafruit config + } + else { // INA219 16V 2A configuration + data.calValue = 40960; + data.powerMultiplier = 2; + data.currentDivider = 10; // 20; in Adafruit config + } + + #ifdef DEBUG_LOGGING + printf("Sensor %s %x configuration: %d %d %d %d %d\n", bus, address, data.fd, + data.config, data.calValue, data.currentDivider, data.powerMultiplier); + #endif + return data; +} + +struct SensorConfig sensor[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorData reading[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorConfig tempSensor; + +char src_addr[5] = ""; +char dest_addr[5] = "CQ"; + +int main(int argc, char *argv[]) { + + if (argc > 1) { + strcpy(src_addr, argv[1]); + } + + wiringPiSetup (); + pinMode (0, OUTPUT); + + //setSpiChannel(SPI_CHANNEL); + //setSpiSpeed(SPI_SPEED); + //initializeSpi(); + + FILE* config_file = fopen("sim.cfg","r"); + if (config_file == NULL) + { + printf("Creating config file."); + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", "KU2Y", 100); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + } + + char* cfg_buf[100]; + fscanf(config_file, "%s %d", call, &reset_count); + fclose(config_file); + printf("%s %d\n", call, reset_count); + + reset_count = (reset_count + 1) % 0xffff; + + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", call, reset_count); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + + tempSensor = config_sensor("/dev/i2c-3", 0x48, 0); + + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); + + int ret; + uint8_t data[1024]; + + tx_freq_hz -= tx_channel * 50000; + + //init_rf(); + + ax25_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) src_addr, '1', + AX25_PREAMBLE_LEN, + AX25_POSTAMBLE_LEN); + + /* Infinite loop */ + //for (;;) + + { + // sleep(1); // Delay 1 second + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting TLM Data\n"); + #endif + + char str[1000]; + // uint8_t b[64]; + char header_str[] = "\x03\xf0"; + strcpy(str, header_str); + + printf("%s-1>%s-1:", (uint8_t *)src_addr, (uint8_t *)dest_addr); + +// get_tlm(str); + get_tlm_fox(); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting ready to send\n"); + #endif + + char cmdbuffer[1000]; + FILE* transmit; + if (DUV == 1) { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/CubeSatSim/rpitx/rpitx -i- -m RF -f 434.9e3 2>&1", "r"); + } else { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr fir_interpolate_cc 2 | csdr dsb_fc | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff | sudo /home/pi/CubeSatSim/rpitx/sendiq -i /dev/stdin -s 96000 -f 434.9e6 -t float 2>&1", "r"); + } + fgets(cmdbuffer, 1000, transmit); + pclose(transmit); + printf("Results of transmit command: %s\n", cmdbuffer); + + + +// printf("%s \n", b); +/* + digitalWrite (0, LOW); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Transmitting X.25 packet\n"); + #endif + memcpy(data, str, strnlen(str, 256)); + ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } + + ax5043_wait_for_transmit(); + + digitalWrite (0, HIGH); + + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } +*/ + } + + return 0; +} + +static void init_rf() { + int ret; + #ifdef DEBUG_LOGGING + fprintf(stderr,"Initializing AX5043\n"); + #endif + ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); + if (ret != PQWS_SUCCESS) { + fprintf(stderr, + "ERROR: Failed to initialize AX5043 with error code %d\n", ret); + exit(EXIT_FAILURE); + } +} + +// Returns lower digit of a number which must be less than 99 +// +int lower_digit(int number) { + + int digit = 0; + if (number < 100) + digit = number - ((int)(number/10) * 10); + else + fprintf(stderr,"ERROR: Not a digit in lower_digit!\n"); + return digit; +} + +// Returns upper digit of a number which must be less than 99 +// +int upper_digit(int number) { + + int digit = 0; + if (number < 100) + digit = (int)(number/10); + else + fprintf(stderr,"ERROR: Not a digit in upper_digit!\n"); + return digit; +} + +int get_tlm(char *str) { + + int tlm[7][5]; + memset(tlm, 0, sizeof tlm); + +// Reading I2C voltage and current sensors + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } + + tlm[1][A] = (int)(reading[BUS].voltage /15.0 + 0.5) % 100; // Current of 5V supply to Pi + tlm[1][B] = (int) (99.5 - reading[PLUS_X].current/10.0) % 100; // +X current [4] + tlm[1][C] = (int) (99.5 - reading[MINUS_X].current/10.0) % 100; // X- current [10] + tlm[1][D] = (int) (99.5 - reading[PLUS_Y].current/10.0) % 100; // +Y current [7] + + tlm[2][A] = (int) (99.5 - reading[MINUS_Y].current/10.0) % 100; // -Y current [10] + tlm[2][B] = (int) (99.5 - reading[PLUS_Z].current/10.0) % 100; // +Z current [10] // was 70/2m transponder power, AO-7 didn't have a Z panel + tlm[2][C] = (int) (99.5 - reading[MINUS_Z].current/10.0) % 100; // -Z current (was timestamp) + tlm[2][D] = (int)(50.5 + reading[BAT].current/10.0) % 100; // NiMH Battery current + + tlm[3][A] = abs((int)((reading[BAT].voltage * 10.0) - 65.5) % 100); + tlm[3][B] = (int)(reading[BUS].voltage * 10.0) % 100; // 5V supply to Pi + + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + tlm[4][A] = (int)((95.8 - temp)/1.48 + 0.5) % 100; + } + + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + tlm[4][B] = (int)((95.8 - cpuTemp)/1.48 + 0.5) % 100; + fclose (cpuTempSensor); + } + + tlm[6][B] = 0 ; + tlm[6][D] = 49 + rand() % 3; + + #ifdef DEBUG_LOGGING +// Display tlm + int k, j; + for (k = 1; k < 7; k++) { + for (j = 1; j < 5; j++) { + printf(" %2d ", tlm[k][j]); + } + printf("\n"); + } + #endif + + char tlm_str[1000]; + + char header_str[] = "hi hi "; + strcpy(str, header_str); +// printf("%s-1>%s-1:hi hi ", (uint8_t *)src_addr, (uint8_t *)dest_addr); + + int channel; + for (channel = 1; channel < 7; channel++) { + sprintf(tlm_str, "%d%d%d %d%d%d %d%d%d %d%d%d ", + channel, upper_digit(tlm[channel][1]), lower_digit(tlm[channel][1]), + channel, upper_digit(tlm[channel][2]), lower_digit(tlm[channel][2]), + channel, upper_digit(tlm[channel][3]), lower_digit(tlm[channel][3]), + channel, upper_digit(tlm[channel][4]), lower_digit(tlm[channel][4])); +// printf("%s",tlm_str); + strcat(str, tlm_str); + } +// printf("\n"); + +return; +} + +int get_tlm_fox() { + +// memset(b, 0, 64); + +// Reading I2C voltage and current sensors +/* + FILE* uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + fclose(uptime_file); +*/ + int i; + long int sync = SYNC_WORD; + + smaller = S_RATE/(2 * freq_Hz); +/* + short int b[DATA_LEN] = {0x00,0x7E,0x03, + 0x00,0x00,0x00,0x00,0xE6,0x01,0x00,0x27,0xD1,0x02, + 0xE5,0x40,0x04,0x18,0xE1,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + short int h[HEADER_LEN] = {0x05,0x00,0x00,0x00,0x00,0x10,0x00,0x00}; +*/ + + short int b[DATA_LEN * PAYLOADS]; // for each payload +// memset(b, 0, sizeof(b)); + + short int h[HEADER_LEN]; +// memset(h, 0, sizeof(h)); + + short int b10[DATA_LEN], h10[HEADER_LEN]; + short int rs_frame[RS_FRAMES][223]; + unsigned char parities[RS_FRAMES][PARITY_LEN],inputByte; +/* + int id = 5, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 8.95 * 100, battCurr = 48.6 * 10; + int posXv = 296, negXv = 45, posYv = 220, negYv = 68, + posZv = 280, negZv = 78; +*/ + int id = 5, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 0, battCurr = 0; + int posXv = 0, negXv = 0, posYv = 0, negYv = 0, + posZv = 0, negZv = 0; + int head_offset = 0; + + for (int frames = 0; frames < FRAME_CNT; frames++) + { + memset(rs_frame,0,sizeof(rs_frame)); + memset(parities,0,sizeof(parities)); + + FILE *uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + fclose(uptime_file); + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + + h[0] = (h[0] & 0xf8) | (id & 0x07); // 3 bits + printf("h[0] %x\n", h[0]); + h[0] = (h[0] & 0x07)| ((reset_count & 0x1f) << 3); + printf("h[0] %x\n", h[0]); + h[1] = (reset_count >> 5) & 0xff; + printf("h[1] %x\n", h[1]); + h[2] = (h[2] & 0xf8) | ((reset_count >> 13) & 0x07); + printf("h[2] %x\n", h[2]); + h[2] = (h[2] & 0x0e) | ((uptime & 0x1f) << 3); + printf("h[2] %x\n", h[2]); + h[3] = (uptime >> 5) & 0xff; + h[4] = (uptime >> 13) & 0xff; + h[5] = (h[5] & 0xf0) | ((uptime >> 21) & 0x0f); + h[5] = (h[5] & 0x0f) | (frm_type << 4); + + + +/* batt_c_v += 10; + battCurr -= 10; + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); +*/ + + int ctr1 = 0; + int ctr3 = 0; + for (i = 0; i < RS_FRAME_LEN; i++) + { + for (int j = 0; j < RS_FRAMES ; j++) + { + + if ((ctr3 % DATA_LEN) == 0) + { + // sleep + // clear b and h + // get uptime and encode in h + // read telem data and encode in b + sleep(1); + + memset(b, 0, sizeof(b)); + memset(h, 0, sizeof(h)); + + FILE *uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + fclose(uptime_file); + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + + h[0] = (h[0] & 0xf8) | (id & 0x07); // 3 bits + printf("h[0] %x\n", h[0]); + h[0] = (h[0] & 0x07)| ((reset_count & 0x1f) << 3); + printf("h[0] %x\n", h[0]); + h[1] = (reset_count >> 5) & 0xff; + printf("h[1] %x\n", h[1]); + h[2] = (h[2] & 0xf8) | ((reset_count >> 13) & 0x07); + printf("h[2] %x\n", h[2]); + h[2] = (h[2] & 0x0e) | ((uptime & 0x1f) << 3); + printf("h[2] %x\n", h[2]); + h[3] = (uptime >> 5) & 0xff; + h[4] = (uptime >> 13) & 0xff; + h[5] = (h[5] & 0xf0) | ((uptime >> 21) & 0x0f); + h[5] = (h[5] & 0x0f) | (frm_type << 4); + + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } +/* + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + TxTemp = (int)((temp * 10.0) + 0.5); + encodeB(b, 34 + head_offset, TxTemp); + } +*/ + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + IHUcpuTemp = (int)((cpuTemp * 10.0) + 0.5); + encodeA(b, 39 + head_offset, IHUcpuTemp); + } +// sleep(1); + + posXv = reading[PLUS_X].current * 10; + posYv = reading[PLUS_Y].current * 10; + posZv = reading[PLUS_Z].current * 10; + negXv = reading[MINUS_X].current * 10; + negYv = reading[MINUS_Y].current * 10; + negZv = reading[MINUS_Z].current * 10; + + batt_c_v = reading[BAT].voltage * 100; + battCurr = reading[BAT].current * 10; + + encodeA(b, 0 + head_offset, batt_a_v); + encodeB(b, 1 + head_offset, batt_b_v); + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); + encodeA(b, 12 + head_offset,posXv); + encodeB(b, 13 + head_offset,posYv); + encodeA(b, 15 + head_offset,posZv); + encodeB(b, 16 + head_offset,negXv); + encodeA(b, 18 + head_offset,negYv); + encodeB(b, 19 + head_offset,negZv); + } + + if (!((i == (RS_FRAME_LEN - 1)) && (j == 2))) // skip last one for BPSK + { + if (ctr1 < HEADER_LEN) + { + rs_frame[j][i] = h[ctr1]; + update_rs(parities[j], h[ctr1]); + // printf("header %d rs_frame[%d][%d] = %x \n", ctr1, j, i, h[ctr1]); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + } + else + { + rs_frame[j][i] = b[ctr3 % DATA_LEN]; + update_rs(parities[j], b[ctr3 % DATA_LEN]); + // printf("%d rs_frame[%d][%d] = %x %d \n", + // ctr1, j, i, b[ctr3 % DATA_LEN], ctr3 % DATA_LEN); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + ctr3++; + } + } + } + } + + printf("Parities "); + for (int m = 0; m < PARITY_LEN; m++) { + printf("%d ", parities[0][m]); + } + printf("\n"); + + int ctr2 = 0; + memset(data10,0,sizeof(data10)); + int rd = 0; + int nrd; + + for (i = 0; i < DATA_LEN * PAYLOADS + HEADER_LEN; i++) // 476 for BPSK + { + data10[ctr2] = (Encode_8b10b[rd][((int)data8[ctr2])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)data8[ctr2])] >> 10) & 1; + // printf ("data10[%d] = encoded data8[%d] = %x \n", + // ctr2, ctr2, data10[ctr2]); + + rd = nrd; // ^ nrd; + ctr2++; + } + + for (i = 0; i < PARITY_LEN; i++) + { + for (int j = 0; j < RS_FRAMES; j++) + { + data10[ctr2++] = (Encode_8b10b[rd][((int)parities[j][i])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)parities[j][i])] >> 10) & 1; + // printf ("data10[%d] = encoded parities[%d][%d] = %x \n", + // ctr2 - 1, j, i, data10[ctr2 - 1]); + + rd = nrd; + } + } + + int data; + int val; + int offset = 0; + + for (i = 1; i <= SYNC_BITS * SAMPLES; i++) + { + write_wave(ctr); + if ( (i % SAMPLES) == 0) { + int bit = SYNC_BITS - i/SAMPLES + 1; + val = sync; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d sync bit %d = %d \n", + // ctr/SAMPLES, i, frames, bit, (data > 0) ); + if (DUV) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + + for (i = 1; + i <= (10 * (HEADER_LEN + DATA_LEN * PAYLOADS + RS_FRAMES * PARITY_LEN) * SAMPLES); i++) // 572 + { + write_wave(ctr); + if ( (i % SAMPLES) == 0) { + int symbol = (int)((i - 1)/ (SAMPLES * 10)); + int bit = 10 - (i - symbol * SAMPLES * 10) / SAMPLES + 1; + val = data10[symbol]; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d data10[%d] = %x bit %d = %d \n", + // ctr/SAMPLES, i, frames, symbol, val, bit, (data > 0) ); + if (DUV) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j ++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + } + write_wav("transmit.wav", BUF_LEN, buffer, S_RATE); + + int count; + for (count = 0; count < DATA_LEN; count++) { + printf("%02X", b[count]); + } + printf("\n"); + +return 0; +} + +// wav file generation code + +/* make_wav.c + * Creates a WAV file from an array of ints. + * Output is monophonic, signed 16-bit samples + * copyright + * Fri Jun 18 16:36:23 PDT 2010 Kevin Karplus + * Creative Commons license Attribution-NonCommercial + * http://creativecommons.org/licenses/by-nc/3.0/ + * + * Edited by Dolin Sergey. dlinyj@gmail.com + * April 11 12:58 2014 + */ + + // gcc -o make_enc_wav make_enc_wav.c -lm + // ./make_enc_wav + + /* + * TelemEncoding.h + * + * Created on: Feb 3, 2014 + * Author: fox + */ + +#include +#include +#include +#include +#include +#include + +//#include "make_wav.h" + +#define false 0 +#define true 1 + +//static int twosToInt(int val,int len); +//static int encodeB(short int *b, int index, int val); +//static int encodeA(short int *b, int index, int val); + + static int NOT_FRAME = /* 0fa */ 0xfa & 0x3ff; + static int FRAME = /* 0fa */ ~0xfa & 0x3ff; + +/* + * TelemEncoding.c + * + Fox-1 telemetry encoder + January 2014 Phil Karn KA9Q + + This file has two external functions: + void update_rs(unsigned char parity[32],unsigned char data); + int encode_8b10b(int *state,int data). + + update_rs() is the Reed-Solomon encoder. Its first argument is the 32-byte + encoder shift register, the second is the 8-bit data byte being encoded. It updates + the shift register in place and returns void. At the end of each frame, it contains + the parities ready for transmission, starting with parity[0]. + Be sure to zero this array before each new frame! + + encode_8b10b() is the 8b10b encoder. Its first argument is a pointer to a single integer + with the 1-bit encoder state (the current run disparity, or RD). Initialize it to 0 + JUST ONCE at startup (not between frames). + The second argument is the data byte being encoded. It updates the state and returns + an integer containing the 10-bit encoded word, right justified. + Transmit this word from left to right. + + The data argument is an int so it can hold the special value -1 to indicate end of frame; + it generates the 8b10b control word K.28.5, which is used as an inter-frame flag. + + Some assert() calls are made to verify legality of arguments. These can be turned off in + production code. + + + sample frame transmission code: + + unsigned char data[64]; // Data block to be sent + unsigned char parity[32]; // RS parities + void transmit_word(int); // User provided transmit function: 10 bits of data in bits 9....0 + int state,i; + + state = 0; // Only once at startup, not between frames + memset(parity,0,sizeof(parity); // Do this before every frame + // Transmit the data, updating the RS encoder + for(i=0;i<64;i++){ + update_rs(parity,data[i]); + transmit_word(encode_8b10b(&state,data[i]); + } + // Transmit the RS parities + for(i=0;i<32;i++) + transmit_word(encode_8b10b(&state,parity[i]); + + transmit_word(encode_8b10b(&state,-1); // Transmit end-of-frame flag +*/ + + +#include +//#include "Fox.h" +//#include "TelemEncoding.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define NN (0xff) // Frame size in symbols +#define A0 (NN) // special value for log(0) + + +// GF Antilog lookup table table +static unsigned char CCSDS_alpha_to[NN+1] = { +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, +0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, +0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, +0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, +0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, +0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, +0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, +0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, +0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, +0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, +0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, +0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, +0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, +0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, +0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, +0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, +}; + +// GF log lookup table. Special value represents log(0) +static unsigned char CCSDS_index_of[NN+1] = { + A0, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, + 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, + 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, +103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, + 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, +202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, +104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, +110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, + 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, +209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, +203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, +192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, +105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, +130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, +111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, + 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, +}; + +// Only half the coefficients are given here because the +// generator polynomial is palindromic; G0 = G32, G1 = G31, etc. +// Only G16 is unique +static unsigned char CCSDS_poly[] = { + 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, + 24, +}; + + +static inline int modnn(int x){ + while (x >= NN) { + x -= NN; + x = (x >> 8) + (x & NN); + } + return x; +} + + +// Update Reed-Solomon encoder +// parity -> 32-byte reed-solomon encoder state; clear this to zero before each frame +void update_rs( + unsigned char parity[32], // 32-byte encoder state; zero before each frame + unsigned char c) // Current data byte to update +{ + unsigned char feedback; + int j,t; + + assert(parity != NULL); + feedback = CCSDS_index_of[c ^ parity[0]]; + if(feedback != A0){ // only if feedback is non-zero + // Take advantage of palindromic polynomial to halve the multiplies + // Do G1...G15, which is the same as G17...G31 + for(j=1;j0) + { buf = word & 0xff; + fwrite(&buf, 1,1, wav_file); + num_bytes--; + word >>= 8; + } +} + +/* information about the WAV file format from + +http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ + + */ + +void write_wav(char * filename, unsigned long num_samples, short int * data, int s_rate) +{ + FILE* wav_file; + unsigned int sample_rate; + unsigned int num_channels; + unsigned int bytes_per_sample; + unsigned int byte_rate; + unsigned long i; /* counter for samples */ + + num_channels = 1; /* monoaural */ + bytes_per_sample = 2; + + if (s_rate<=0) sample_rate = 44100; + else sample_rate = (unsigned int) s_rate; + + byte_rate = sample_rate*num_channels*bytes_per_sample; + + wav_file = fopen(filename, "w"); + assert(wav_file); /* make sure it opened */ + + /* write RIFF header */ + fwrite("RIFF", 1, 4, wav_file); + write_little_endian(36 + bytes_per_sample* num_samples*num_channels, 4, wav_file); + fwrite("WAVE", 1, 4, wav_file); + + /* write fmt subchunk */ + fwrite("fmt ", 1, 4, wav_file); + write_little_endian(16, 4, wav_file); /* SubChunk1Size is 16 */ + write_little_endian(1, 2, wav_file); /* PCM is format 1 */ + write_little_endian(num_channels, 2, wav_file); + write_little_endian(sample_rate, 4, wav_file); + write_little_endian(byte_rate, 4, wav_file); + write_little_endian(num_channels*bytes_per_sample, 2, wav_file); /* block align */ + write_little_endian(8*bytes_per_sample, 2, wav_file); /* bits/sample */ + + /* write data subchunk */ + fwrite("data", 1, 4, wav_file); + write_little_endian(bytes_per_sample* num_samples*num_channels, 4, wav_file); + + for (i=0; i< num_samples; i++) + { write_little_endian((unsigned int)(data[i]),bytes_per_sample, wav_file); + } + + fclose(wav_file); +} + + + +//int main(int argc, char * argv[]) +//{ + +// return 0; +//} + +void write_wave(int i) +{ + if (DUV) + { +// if ((ctr - flip_ctr) < smaller) +// buffer[ctr++] = 0.1 * phase * (ctr - flip_ctr) / smaller; +// else + buffer[ctr++] = 0.25 * amplitude * phase; + } + else + { + if ((ctr - flip_ctr) < smaller) + buffer[ctr++] = (int)(amplitude * 0.4 * phase * + sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + else + buffer[ctr++] = (int)(amplitude * phase * + sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + } +// printf("%d %d \n", i, buffer[ctr - 1]); + +} + +/** + * + * FOX 1 Telemetry Decoder + * @author chris.e.thompson g0kla/ac2cz + * + * Copyright (C) 2015 amsat.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General 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 License for more details. + * + * You should have received a copy of the GNU General License + * along with this program. If not, see . + * + * + * Static variables and methods to encode and decode 8b10b + * + * + */ + +int encodeA(short int *b, int index, int val) { +// printf("Encoding A\n"); + b[index] = val & 0xff; + b[index + 1] = (b[index + 1] & 0xf0) | ((val >> 8) & 0x0f); + return 0; +} + +int encodeB(short int *b, int index, int val) { +// printf("Encoding B\n"); + b[index] = (b[index] & 0x0f) | ((val << 4) & 0xf0); + b[index + 1] = (val >> 4 ) & 0xff; + return 0; +} + +int twosToInt(int val,int len) { // Convert twos compliment to integer +// from https://www.raspberrypi.org/forums/viewtopic.php?t=55815 + + if(val & (1 << (len - 1))) + val = val - (1 << len); + + return(val); +} diff --git a/afsk/main3.c b/afsk/main3.c new file mode 100644 index 00000000..5e344633 --- /dev/null +++ b/afsk/main3.c @@ -0,0 +1,1126 @@ +/* + * Transmits CubeSat Telemetry at 434.9MHz in AO-7 format + * + * Copyright Alan B. Johnston + * + * Portions Copyright (C) 2018 Jonathan Brandenburg + * + * 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 . + * + * INA219 Raspberry Pi wiringPi code is based on Adafruit Arduino wire code + * from https://github.com/adafruit/Adafruit_INA219. + */ + +#include +#include +#include +#include +#include +#include "status.h" +#include "ax5043.h" +#include "ax25.h" +#include "spi/ax5043spi.h" +#include +#include +#include +#include +#include "Adafruit_INA219.h" // From Adafruit INA219 library for Arduino +#include "make_wav.h" + +#define A 1 +#define B 2 +#define C 3 +#define D 4 + +#define PLUS_X 0 +#define PLUS_Y 1 +#define PLUS_Z 2 +#define BAT 3 +#define MINUS_X 4 +#define MINUS_Y 5 +#define MINUS_Z 6 +#define BUS 7 +#define OFF -1 + +uint32_t tx_freq_hz = 434900000 + FREQUENCY_OFFSET; +uint32_t tx_channel = 0; + +ax5043_conf_t hax5043; +ax25_conf_t hax25; + +static void init_rf(); +int twosToInt(int val, int len); +int get_tlm(char *str); +int get_tlm_fox(); +int encodeA(short int *b, int index, int val); +int encodeB(short int *b, int index, int val); +void config_x25(); +void trans_x25(); +int upper_digit(int number); +int lower_digit(int number); + +#define S_RATE (48000) // (44100) +#define BUF_SIZE (S_RATE*10) /* 2 second buffer */ + +// BPSK Settings +#define BIT_RATE 1200 // 200 for DUV +#define DUV 0 // 1 for DUV +#define RS_FRAMES 3 // 3 frames for BPSK, 1 for DUV +#define PAYLOADS 6 // 1 for DUV +#define DATA_LEN 78 // 56 for DUV +#define RS_FRAME_LEN 159 // 64 for DUV +#define SYNC_BITS 31 // 10 for DUV +#define SYNC_WORD 0b1000111110011010010000101011101 // 0b0011111010 for DUV +#define HEADER_LEN 8 // 6 for DUV +/* +// DUV Settings +#define BIT_RATE 200 +#define DUV 1 +#define RS_FRAMES 1 +#define PAYLOADS 1 +#define RS_FRAME_LEN 64 +#define HEADER_LEN 6 +#define DATA_LEN 58 +#define SYNC_BITS 10 +#define SYNC_WORD 0b0011111010 +*/ + +#define PARITY_LEN 32 + +float amplitude = 32767/3; // 20000; // 32767/(10%amp+5%amp+100%amp) +float freq_Hz = 3000; // 1200 + +int smaller; +int flip_ctr = 0; +int phase = 1; +int ctr = 0; +long int ptr = 0; + +void copy_samples(); +void write_to_buffer(int i, int symbol, int val); +void write_wave(); +#define SAMPLES (S_RATE / BIT_RATE) +#define FRAME_CNT 33 // Add 3 frames to the count + +//#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (8 + 6 * DATA_LEN + 96)) * SAMPLES) +#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN))) * SAMPLES) +short int buffer[BUF_LEN]; +short int phase0[SAMPLES], phase1[SAMPLES]; +int size_of_phase; +short int data10[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +short int data8[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +int reset_count; +float uptime_sec; +long int uptime; +char call[5]; + +struct SensorConfig { + int fd; + uint16_t config; + int calValue; + int powerMultiplier; + int currentDivider; +}; + +struct SensorData { + double current; + double voltage; + double power; +}; + +/** + * @brief Read the data from one of the i2c current sensors. + * + * Reads the current data from the requested i2c current sensor configuration and + * stores it into a SensorData struct. An invalid file descriptor (i.e. less than zero) + * results in a SensorData struct being returned that has both its #current and #power members + * set to NAN. + * + * @param sensor A structure containing sensor configuration including the file descriptor. + * @return struct SensorData A struct that contains the current, voltage, and power readings + * from the requested sensor. + */ +struct SensorData read_sensor_data(struct SensorConfig sensor) { + struct SensorData data = { + .current = NAN, + .voltage = NAN, + .power = NAN }; + + if (sensor.fd < 0) { + return data; + } + // doesn't read negative currents accurately, shows -0.1mA + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CONFIG, sensor.config); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + int value = wiringPiI2CReadReg16(sensor.fd, INA219_REG_CURRENT); + data.current = (float) twosToInt(value, 16) / (float) sensor.currentDivider; + + wiringPiI2CWrite(sensor.fd, INA219_REG_BUSVOLTAGE); + delay(1); // Max 12-bit conversion time is 586us per sample + value = (wiringPiI2CRead(sensor.fd) << 8 ) | wiringPiI2CRead (sensor.fd); + data.voltage = ((float)(value >> 3) * 4) / 1000; + // power has very low resolution, seems to step in 512mW values + data.power = (float) wiringPiI2CReadReg16(sensor.fd, INA219_REG_POWER) * (float) sensor.powerMultiplier; + + return data; +} + +/** + * @brief Configures an i2c current sensor. + * + * Calculates the configuration values of the i2c sensor so that + * current, voltage, and power can be read using read_sensor_data. + * Supports 16V 400mA and 16V 2.0A settings. + * + * @param sensor A file descriptor that can be used to read from the sensor. + * @param milliAmps The mA configuration, either 400mA or 2A are supported. + * @return struct SensorConfig A struct that contains the configuraton of the sensor. + */ +//struct SensorConfig config_sensor(int sensor, int milliAmps) { +struct SensorConfig config_sensor(char *bus, int address, int milliAmps) { + struct SensorConfig data; + + if (access(bus, W_OK | R_OK) < 0) { // Test if I2C Bus is missing + printf("ERROR: %s bus not present \n", bus); + data.fd = OFF; + return (data); + } + + data.fd = wiringPiI2CSetupInterface(bus, address); + + data.config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_1_40MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_1S_532US | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + if (milliAmps == 400) { // INA219 16V 400mA configuration + data.calValue = 8192; + data.powerMultiplier = 1; + data.currentDivider = 20; // 40; in Adafruit config + } + else { // INA219 16V 2A configuration + data.calValue = 40960; + data.powerMultiplier = 2; + data.currentDivider = 10; // 20; in Adafruit config + } + + #ifdef DEBUG_LOGGING + printf("Sensor %s %x configuration: %d %d %d %d %d\n", bus, address, data.fd, + data.config, data.calValue, data.currentDivider, data.powerMultiplier); + #endif + return data; +} + +struct SensorConfig sensor[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorData reading[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorConfig tempSensor; + +char src_addr[5] = ""; +char dest_addr[5] = "CQ"; + +int main(int argc, char *argv[]) { + + if (argc > 1) { + strcpy(src_addr, argv[1]); + } + + wiringPiSetup (); + pinMode (0, OUTPUT); + + //setSpiChannel(SPI_CHANNEL); + //setSpiSpeed(SPI_SPEED); + //initializeSpi(); + + FILE* config_file = fopen("sim.cfg","r"); + if (config_file == NULL) + { + printf("Creating config file."); + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", "KU2Y", 100); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + } + + char* cfg_buf[100]; + fscanf(config_file, "%s %d", call, &reset_count); + fclose(config_file); + printf("%s %d\n", call, reset_count); + + reset_count = (reset_count + 1) % 0xffff; + + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", call, reset_count); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + + tempSensor = config_sensor("/dev/i2c-3", 0x48, 0); + + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); + + int ret; + uint8_t data[1024]; + + tx_freq_hz -= tx_channel * 50000; + + //init_rf(); + + ax25_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) src_addr, '1', + AX25_PREAMBLE_LEN, + AX25_POSTAMBLE_LEN); + + /* Infinite loop */ + //for (;;) + + { + // sleep(1); // Delay 1 second + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting TLM Data\n"); + #endif + + char str[1000]; + // uint8_t b[64]; + char header_str[] = "\x03\xf0"; + strcpy(str, header_str); + + printf("%s-1>%s-1:", (uint8_t *)src_addr, (uint8_t *)dest_addr); + +// get_tlm(str); + get_tlm_fox(); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting ready to send\n"); + #endif + + char cmdbuffer[1000]; + FILE* transmit; + if (DUV == 1) { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/CubeSatSim/rpitx/rpitx -i- -m RF -f 434.9e3 2>&1", "r"); + } else { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr fir_interpolate_cc 2 | csdr dsb_fc | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff | sudo /home/pi/CubeSatSim/rpitx/sendiq -i /dev/stdin -s 96000 -f 434.9e6 -t float 2>&1", "r"); + } + fgets(cmdbuffer, 1000, transmit); + pclose(transmit); + printf("Results of transmit command: %s\n", cmdbuffer); + + + +// printf("%s \n", b); +/* + digitalWrite (0, LOW); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Transmitting X.25 packet\n"); + #endif + memcpy(data, str, strnlen(str, 256)); + ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } + + ax5043_wait_for_transmit(); + + digitalWrite (0, HIGH); + + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } +*/ + } + + return 0; +} + +static void init_rf() { + int ret; + #ifdef DEBUG_LOGGING + fprintf(stderr,"Initializing AX5043\n"); + #endif + ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); + if (ret != PQWS_SUCCESS) { + fprintf(stderr, + "ERROR: Failed to initialize AX5043 with error code %d\n", ret); + exit(EXIT_FAILURE); + } +} + +// Returns lower digit of a number which must be less than 99 +// +int lower_digit(int number) { + + int digit = 0; + if (number < 100) + digit = number - ((int)(number/10) * 10); + else + fprintf(stderr,"ERROR: Not a digit in lower_digit!\n"); + return digit; +} + +// Returns upper digit of a number which must be less than 99 +// +int upper_digit(int number) { + + int digit = 0; + if (number < 100) + digit = (int)(number/10); + else + fprintf(stderr,"ERROR: Not a digit in upper_digit!\n"); + return digit; +} + +int get_tlm(char *str) { + + int tlm[7][5]; + memset(tlm, 0, sizeof tlm); + +// Reading I2C voltage and current sensors + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } + + tlm[1][A] = (int)(reading[BUS].voltage /15.0 + 0.5) % 100; // Current of 5V supply to Pi + tlm[1][B] = (int) (99.5 - reading[PLUS_X].current/10.0) % 100; // +X current [4] + tlm[1][C] = (int) (99.5 - reading[MINUS_X].current/10.0) % 100; // X- current [10] + tlm[1][D] = (int) (99.5 - reading[PLUS_Y].current/10.0) % 100; // +Y current [7] + + tlm[2][A] = (int) (99.5 - reading[MINUS_Y].current/10.0) % 100; // -Y current [10] + tlm[2][B] = (int) (99.5 - reading[PLUS_Z].current/10.0) % 100; // +Z current [10] // was 70/2m transponder power, AO-7 didn't have a Z panel + tlm[2][C] = (int) (99.5 - reading[MINUS_Z].current/10.0) % 100; // -Z current (was timestamp) + tlm[2][D] = (int)(50.5 + reading[BAT].current/10.0) % 100; // NiMH Battery current + + tlm[3][A] = abs((int)((reading[BAT].voltage * 10.0) - 65.5) % 100); + tlm[3][B] = (int)(reading[BUS].voltage * 10.0) % 100; // 5V supply to Pi + + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + tlm[4][A] = (int)((95.8 - temp)/1.48 + 0.5) % 100; + } + + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + tlm[4][B] = (int)((95.8 - cpuTemp)/1.48 + 0.5) % 100; + fclose (cpuTempSensor); + } + + tlm[6][B] = 0 ; + tlm[6][D] = 49 + rand() % 3; + + #ifdef DEBUG_LOGGING +// Display tlm + int k, j; + for (k = 1; k < 7; k++) { + for (j = 1; j < 5; j++) { + printf(" %2d ", tlm[k][j]); + } + printf("\n"); + } + #endif + + char tlm_str[1000]; + + char header_str[] = "hi hi "; + strcpy(str, header_str); +// printf("%s-1>%s-1:hi hi ", (uint8_t *)src_addr, (uint8_t *)dest_addr); + + int channel; + for (channel = 1; channel < 7; channel++) { + sprintf(tlm_str, "%d%d%d %d%d%d %d%d%d %d%d%d ", + channel, upper_digit(tlm[channel][1]), lower_digit(tlm[channel][1]), + channel, upper_digit(tlm[channel][2]), lower_digit(tlm[channel][2]), + channel, upper_digit(tlm[channel][3]), lower_digit(tlm[channel][3]), + channel, upper_digit(tlm[channel][4]), lower_digit(tlm[channel][4])); +// printf("%s",tlm_str); + strcat(str, tlm_str); + } +// printf("\n"); + +return; +} + +int get_tlm_fox() { + +// memset(b, 0, 64); + +// Reading I2C voltage and current sensors + + FILE* uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + fclose(uptime_file); + + int i; + long int sync = SYNC_WORD; + + smaller = S_RATE/(2 * freq_Hz); +/* + short int b[DATA_LEN] = {0x00,0x7E,0x03, + 0x00,0x00,0x00,0x00,0xE6,0x01,0x00,0x27,0xD1,0x02, + 0xE5,0x40,0x04,0x18,0xE1,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + short int h[HEADER_LEN] = {0x05,0x00,0x00,0x00,0x00,0x10,0x00,0x00}; +*/ + + short int b[DATA_LEN]; + memset(b, 0, sizeof(b)); + + short int h[HEADER_LEN]; + memset(h, 0, sizeof(h)); + + short int b10[DATA_LEN], h10[HEADER_LEN]; + short int rs_frame[RS_FRAMES][223]; + unsigned char parities[RS_FRAMES][PARITY_LEN],inputByte; +/* + int id = 5, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 8.95 * 100, battCurr = 48.6 * 10; + int posXv = 296, negXv = 45, posYv = 220, negYv = 68, + posZv = 280, negZv = 78; +*/ + int id = 5, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 0, battCurr = 0; + int posXv = 0, negXv = 0, posYv = 0, negYv = 0, + posZv = 0, negZv = 0; + int head_offset = 0; + + for (int frames = 0; frames < FRAME_CNT; frames++) + { + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } +/* + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + TxTemp = (int)((temp * 10.0) + 0.5); + encodeB(b, 34 + head_offset, TxTemp); + } +*/ + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + IHUcpuTemp = (int)((cpuTemp * 10.0) + 0.5); + encodeA(b, 39 + head_offset, IHUcpuTemp); + } + sleep(1); + + memset(rs_frame,0,sizeof(rs_frame)); + memset(parities,0,sizeof(parities)); + + FILE *uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + fclose(uptime_file); + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + + h[0] = (h[0] & 0xf8) | (id & 0x07); // 3 bits + printf("h[0] %x\n", h[0]); + h[0] = (h[0] & 0x07)| ((reset_count & 0x1f) << 3); + printf("h[0] %x\n", h[0]); + h[1] = (reset_count >> 5) & 0xff; + printf("h[1] %x\n", h[1]); + h[2] = (h[2] & 0xf8) | ((reset_count >> 13) & 0x07); + printf("h[2] %x\n", h[2]); + h[2] = (h[2] & 0x0e) | ((uptime & 0x1f) << 3); + printf("h[2] %x\n", h[2]); + h[3] = (uptime >> 5) & 0xff; + h[4] = (uptime >> 13) & 0xff; + h[5] = (h[5] & 0xf0) | ((uptime >> 21) & 0x0f); + h[5] = (h[5] & 0x0f) | (frm_type << 4); + + posXv = reading[PLUS_X].current * 10; + posYv = reading[PLUS_Y].current * 10; + posZv = reading[PLUS_Z].current * 10; + negXv = reading[MINUS_X].current * 10; + negYv = reading[MINUS_Y].current * 10; + negZv = reading[MINUS_Z].current * 10; + + batt_c_v = reading[BAT].voltage * 100; + battCurr = reading[BAT].current * 10; + + encodeA(b, 0 + head_offset, batt_a_v); + encodeB(b, 1 + head_offset, batt_b_v); + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); + encodeA(b, 12 + head_offset,posXv); + encodeB(b, 13 + head_offset,posYv); + encodeA(b, 15 + head_offset,posZv); + encodeB(b, 16 + head_offset,negXv); + encodeA(b, 18 + head_offset,negYv); + encodeB(b, 19 + head_offset,negZv); + +/* batt_c_v += 10; + battCurr -= 10; + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); +*/ + int ctr1 = 0; + int ctr3 = 0; + for (i = 0; i < RS_FRAME_LEN; i++) + { + for (int j = 0; j < RS_FRAMES ; j++) + { + if (!((i == (RS_FRAME_LEN - 1)) && (j == 2))) // skip last one for BPSK + { + if (ctr1 < HEADER_LEN) + { + rs_frame[j][i] = h[ctr1]; + update_rs(parities[j], h[ctr1]); + // printf("header %d rs_frame[%d][%d] = %x \n", ctr1, j, i, h[ctr1]); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + } + else + { + rs_frame[j][i] = b[ctr3 % DATA_LEN]; + update_rs(parities[j], b[ctr3 % DATA_LEN]); + // printf("%d rs_frame[%d][%d] = %x %d \n", + // ctr1, j, i, b[ctr3 % DATA_LEN], ctr3 % DATA_LEN); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + ctr3++; + } + } + } + } + + printf("Parities "); + for (int m = 0; m < PARITY_LEN; m++) { + printf("%d ", parities[0][m]); + } + printf("\n"); + + int ctr2 = 0; + memset(data10,0,sizeof(data10)); + int rd = 0; + int nrd; + + for (i = 0; i < DATA_LEN * PAYLOADS + HEADER_LEN; i++) // 476 for BPSK + { + data10[ctr2] = (Encode_8b10b[rd][((int)data8[ctr2])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)data8[ctr2])] >> 10) & 1; + // printf ("data10[%d] = encoded data8[%d] = %x \n", + // ctr2, ctr2, data10[ctr2]); + + rd = nrd; // ^ nrd; + ctr2++; + } + + for (i = 0; i < PARITY_LEN; i++) + { + for (int j = 0; j < RS_FRAMES; j++) + { + data10[ctr2++] = (Encode_8b10b[rd][((int)parities[j][i])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)parities[j][i])] >> 10) & 1; + // printf ("data10[%d] = encoded parities[%d][%d] = %x \n", + // ctr2 - 1, j, i, data10[ctr2 - 1]); + + rd = nrd; + } + } + + int data; + int val; + int offset = 0; + ptr = 0; + size_of_phase = sizeof(phase0); + + phase = 1; + for (i = 0; i < SAMPLES; i++) + { + write_wave(i, phase1); + } + phase = 0 + for (i = 0; i < SAMPLES; i++) + { + write_wave(i, phase0); + } + + for (i = 1; i <= SYNC_BITS; i++) + { + copy_samples(); + if ( (i % SAMPLES) == 0) { + int bit = SYNC_BITS - i + 1; + val = sync; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d sync bit %d = %d \n", + // ctr, i, frames, bit, (data > 0) ); + if (DUV) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; +// if ( (ctr - smaller) > 0) +// { +// for (int j = 1; j <= smaller; j++) +// buffer[ctr - j] = buffer[ctr - j] * 0.4; +// } +// flip_ctr = ctr; + } + } + } + } + + for (i = 1; + i <= (10 * (HEADER_LEN + DATA_LEN * PAYLOADS + RS_FRAMES * PARITY_LEN) * 1); i++) // 572 + { + copy_samples(); +// if ( (i % SAMPLES) == 0) { + int symbol = (int)((i - 1)/ 10); + int bit = 10 - (i - symbol * 10); + val = data10[symbol]; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d data10[%d] = %x bit %d = %d \n", + // ctr/SAMPLES, i, frames, symbol, val, bit, (data > 0) ); + if (DUV) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; +// if ( (ctr - smaller) > 0) +// { +// for (int j = 1; j <= smaller; j ++) +// buffer[ctr - j] = buffer[ctr - j] * 0.4; +// } +// flip_ctr = ctr; + } + } +// } + } + } + write_wav("transmit.wav", BUF_LEN, buffer, S_RATE); + + int count; + for (count = 0; count < DATA_LEN; count++) { + printf("%02X", b[count]); + } + printf("\n"); + +return 0; +} + +// wav file generation code + +/* make_wav.c + * Creates a WAV file from an array of ints. + * Output is monophonic, signed 16-bit samples + * copyright + * Fri Jun 18 16:36:23 PDT 2010 Kevin Karplus + * Creative Commons license Attribution-NonCommercial + * http://creativecommons.org/licenses/by-nc/3.0/ + * + * Edited by Dolin Sergey. dlinyj@gmail.com + * April 11 12:58 2014 + */ + + // gcc -o make_enc_wav make_enc_wav.c -lm + // ./make_enc_wav + + /* + * TelemEncoding.h + * + * Created on: Feb 3, 2014 + * Author: fox + */ + +#include +#include +#include +#include +#include +#include + +//#include "make_wav.h" + +#define false 0 +#define true 1 + +//static int twosToInt(int val,int len); +//static int encodeB(short int *b, int index, int val); +//static int encodeA(short int *b, int index, int val); + + static int NOT_FRAME = /* 0fa */ 0xfa & 0x3ff; + static int FRAME = /* 0fa */ ~0xfa & 0x3ff; + +/* + * TelemEncoding.c + * + Fox-1 telemetry encoder + January 2014 Phil Karn KA9Q + + This file has two external functions: + void update_rs(unsigned char parity[32],unsigned char data); + int encode_8b10b(int *state,int data). + + update_rs() is the Reed-Solomon encoder. Its first argument is the 32-byte + encoder shift register, the second is the 8-bit data byte being encoded. It updates + the shift register in place and returns void. At the end of each frame, it contains + the parities ready for transmission, starting with parity[0]. + Be sure to zero this array before each new frame! + + encode_8b10b() is the 8b10b encoder. Its first argument is a pointer to a single integer + with the 1-bit encoder state (the current run disparity, or RD). Initialize it to 0 + JUST ONCE at startup (not between frames). + The second argument is the data byte being encoded. It updates the state and returns + an integer containing the 10-bit encoded word, right justified. + Transmit this word from left to right. + + The data argument is an int so it can hold the special value -1 to indicate end of frame; + it generates the 8b10b control word K.28.5, which is used as an inter-frame flag. + + Some assert() calls are made to verify legality of arguments. These can be turned off in + production code. + + + sample frame transmission code: + + unsigned char data[64]; // Data block to be sent + unsigned char parity[32]; // RS parities + void transmit_word(int); // User provided transmit function: 10 bits of data in bits 9....0 + int state,i; + + state = 0; // Only once at startup, not between frames + memset(parity,0,sizeof(parity); // Do this before every frame + // Transmit the data, updating the RS encoder + for(i=0;i<64;i++){ + update_rs(parity,data[i]); + transmit_word(encode_8b10b(&state,data[i]); + } + // Transmit the RS parities + for(i=0;i<32;i++) + transmit_word(encode_8b10b(&state,parity[i]); + + transmit_word(encode_8b10b(&state,-1); // Transmit end-of-frame flag +*/ + + +#include +//#include "Fox.h" +//#include "TelemEncoding.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define NN (0xff) // Frame size in symbols +#define A0 (NN) // special value for log(0) + + +// GF Antilog lookup table table +static unsigned char CCSDS_alpha_to[NN+1] = { +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, +0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, +0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, +0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, +0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, +0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, +0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, +0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, +0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, +0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, +0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, +0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, +0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, +0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, +0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, +0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, +}; + +// GF log lookup table. Special value represents log(0) +static unsigned char CCSDS_index_of[NN+1] = { + A0, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, + 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, + 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, +103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, + 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, +202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, +104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, +110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, + 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, +209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, +203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, +192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, +105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, +130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, +111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, + 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, +}; + +// Only half the coefficients are given here because the +// generator polynomial is palindromic; G0 = G32, G1 = G31, etc. +// Only G16 is unique +static unsigned char CCSDS_poly[] = { + 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, + 24, +}; + + +static inline int modnn(int x){ + while (x >= NN) { + x -= NN; + x = (x >> 8) + (x & NN); + } + return x; +} + + +// Update Reed-Solomon encoder +// parity -> 32-byte reed-solomon encoder state; clear this to zero before each frame +void update_rs( + unsigned char parity[32], // 32-byte encoder state; zero before each frame + unsigned char c) // Current data byte to update +{ + unsigned char feedback; + int j,t; + + assert(parity != NULL); + feedback = CCSDS_index_of[c ^ parity[0]]; + if(feedback != A0){ // only if feedback is non-zero + // Take advantage of palindromic polynomial to halve the multiplies + // Do G1...G15, which is the same as G17...G31 + for(j=1;j0) + { buf = word & 0xff; + fwrite(&buf, 1,1, wav_file); + num_bytes--; + word >>= 8; + } +} + +/* information about the WAV file format from + +http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ + + */ + +void write_wav(char * filename, unsigned long num_samples, short int * data, int s_rate) +{ + FILE* wav_file; + unsigned int sample_rate; + unsigned int num_channels; + unsigned int bytes_per_sample; + unsigned int byte_rate; + unsigned long i; /* counter for samples */ + + num_channels = 1; /* monoaural */ + bytes_per_sample = 2; + + if (s_rate<=0) sample_rate = 44100; + else sample_rate = (unsigned int) s_rate; + + byte_rate = sample_rate*num_channels*bytes_per_sample; + + wav_file = fopen(filename, "w"); + assert(wav_file); /* make sure it opened */ + + /* write RIFF header */ + fwrite("RIFF", 1, 4, wav_file); + write_little_endian(36 + bytes_per_sample* num_samples*num_channels, 4, wav_file); + fwrite("WAVE", 1, 4, wav_file); + + /* write fmt subchunk */ + fwrite("fmt ", 1, 4, wav_file); + write_little_endian(16, 4, wav_file); /* SubChunk1Size is 16 */ + write_little_endian(1, 2, wav_file); /* PCM is format 1 */ + write_little_endian(num_channels, 2, wav_file); + write_little_endian(sample_rate, 4, wav_file); + write_little_endian(byte_rate, 4, wav_file); + write_little_endian(num_channels*bytes_per_sample, 2, wav_file); /* block align */ + write_little_endian(8*bytes_per_sample, 2, wav_file); /* bits/sample */ + + /* write data subchunk */ + fwrite("data", 1, 4, wav_file); + write_little_endian(bytes_per_sample* num_samples*num_channels, 4, wav_file); + + for (i=0; i< num_samples; i++) + { write_little_endian((unsigned int)(data[i]),bytes_per_sample, wav_file); + } + + fclose(wav_file); +} + + + +//int main(int argc, char * argv[]) +//{ + +// return 0; +//} + +void write_wave(int i, short int *buf) +{ + if (DUV) + { +// if ((ctr - flip_ctr) < smaller) +// buffer[ctr++] = 0.1 * phase * (ctr - flip_ctr) / smaller; +// else + buf[i] = 0.25 * amplitude * phase; + } + else + { +// if ((ctr - flip_ctr) < smaller) + // buffer[ctr++] = (int)(amplitude * 0.4 * phase * + // sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + // else + buf[i] = (int)(amplitude * phase * sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + } + printf("%d %d \n", i, buf[i]); +} + +void copy_samples() +{ + if (phase == 0) + memcpy(buffer[ptr], phase0, size_of_phase); + else + memcpy(buffer[ptr], phase1, size_of_phase); + + ptr += size_of_phase; +} + +/** + * + * FOX 1 Telemetry Decoder + * @author chris.e.thompson g0kla/ac2cz + * + * Copyright (C) 2015 amsat.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General 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 License for more details. + * + * You should have received a copy of the GNU General License + * along with this program. If not, see . + * + * + * Static variables and methods to encode and decode 8b10b + * + * + */ + +int encodeA(short int *b, int index, int val) { +// printf("Encoding A\n"); + b[index] = val & 0xff; + b[index + 1] = (b[index + 1] & 0xf0) | ((val >> 8) & 0x0f); + return 0; +} + +int encodeB(short int *b, int index, int val) { +// printf("Encoding B\n"); + b[index] = (b[index] & 0x0f) | ((val << 4) & 0xf0); + b[index + 1] = (val >> 4 ) & 0xff; + return 0; +} + +int twosToInt(int val,int len) { // Convert twos compliment to integer +// from https://www.raspberrypi.org/forums/viewtopic.php?t=55815 + + if(val & (1 << (len - 1))) + val = val - (1 << len); + + return(val); +} diff --git a/afsk/main4.c b/afsk/main4.c new file mode 100644 index 00000000..9b03fc06 --- /dev/null +++ b/afsk/main4.c @@ -0,0 +1,1100 @@ +/* + * Transmits CubeSat Telemetry at 434.9MHz in AO-7 format + * + * Copyright Alan B. Johnston + * + * Portions Copyright (C) 2018 Jonathan Brandenburg + * + * 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 . + * + * INA219 Raspberry Pi wiringPi code is based on Adafruit Arduino wire code + * from https://github.com/adafruit/Adafruit_INA219. + */ + +#include +#include +#include +#include +#include +#include "status.h" +#include "ax5043.h" +#include "ax25.h" +#include "spi/ax5043spi.h" +#include +#include +#include +#include +#include "Adafruit_INA219.h" // From Adafruit INA219 library for Arduino +#include "make_wav.h" + +#define A 1 +#define B 2 +#define C 3 +#define D 4 + +#define PLUS_X 0 +#define PLUS_Y 1 +#define PLUS_Z 2 +#define BAT 3 +#define MINUS_X 4 +#define MINUS_Y 5 +#define MINUS_Z 6 +#define BUS 7 +#define OFF -1 + +uint32_t tx_freq_hz = 434900000 + FREQUENCY_OFFSET; +uint32_t tx_channel = 0; + +ax5043_conf_t hax5043; +ax25_conf_t hax25; + +static void init_rf(); +int twosToInt(int val, int len); +int get_tlm(char *str); +int get_tlm_fox(); +int encodeA(short int *b, int index, int val); +int encodeB(short int *b, int index, int val); +void config_x25(); +void trans_x25(); +int upper_digit(int number); +int lower_digit(int number); + +#define S_RATE (48000) // (44100) +#define BUF_SIZE (S_RATE*10) /* 2 second buffer */ + +// BPSK Settings +#define BIT_RATE 1200 // 200 for DUV +#define DUV 0 // 1 for DUV +#define RS_FRAMES 3 // 3 frames for BPSK, 1 for DUV +#define PAYLOADS 6 // 1 for DUV +#define DATA_LEN 78 // 56 for DUV +#define RS_FRAME_LEN 159 // 64 for DUV +#define SYNC_BITS 31 // 10 for DUV +#define SYNC_WORD 0b1000111110011010010000101011101 // 0b0011111010 for DUV +#define HEADER_LEN 8 // 6 for DUV +/* +// DUV Settings +#define BIT_RATE 200 +#define DUV 1 +#define RS_FRAMES 1 +#define PAYLOADS 1 +#define RS_FRAME_LEN 64 +#define HEADER_LEN 6 +#define DATA_LEN 58 +#define SYNC_BITS 10 +#define SYNC_WORD 0b0011111010 +*/ + +#define PARITY_LEN 32 + +float amplitude = 32767/3; // 20000; // 32767/(10%amp+5%amp+100%amp) +float freq_Hz = 3000; // 1200 + +int smaller; +int flip_ctr = 0; +int phase = 1; +int ctr = 0; +void write_to_buffer(int i, int symbol, int val); +void write_wave(); +#define SAMPLES (S_RATE / BIT_RATE) +#define FRAME_CNT 33 // Add 3 frames to the count + +//#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (8 + 6 * DATA_LEN + 96)) * SAMPLES) +#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN))) * SAMPLES) +short int buffer[BUF_LEN]; +short int data10[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +short int data8[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +int reset_count; +float uptime_sec; +long int uptime; +char call[5]; + +struct SensorConfig { + int fd; + uint16_t config; + int calValue; + int powerMultiplier; + int currentDivider; +}; + +struct SensorData { + double current; + double voltage; + double power; +}; + +/** + * @brief Read the data from one of the i2c current sensors. + * + * Reads the current data from the requested i2c current sensor configuration and + * stores it into a SensorData struct. An invalid file descriptor (i.e. less than zero) + * results in a SensorData struct being returned that has both its #current and #power members + * set to NAN. + * + * @param sensor A structure containing sensor configuration including the file descriptor. + * @return struct SensorData A struct that contains the current, voltage, and power readings + * from the requested sensor. + */ +struct SensorData read_sensor_data(struct SensorConfig sensor) { + struct SensorData data = { + .current = NAN, + .voltage = NAN, + .power = NAN }; + + if (sensor.fd < 0) { + return data; + } + // doesn't read negative currents accurately, shows -0.1mA + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CONFIG, sensor.config); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + int value = wiringPiI2CReadReg16(sensor.fd, INA219_REG_CURRENT); + data.current = (float) twosToInt(value, 16) / (float) sensor.currentDivider; + + wiringPiI2CWrite(sensor.fd, INA219_REG_BUSVOLTAGE); + delay(1); // Max 12-bit conversion time is 586us per sample + value = (wiringPiI2CRead(sensor.fd) << 8 ) | wiringPiI2CRead (sensor.fd); + data.voltage = ((float)(value >> 3) * 4) / 1000; + // power has very low resolution, seems to step in 512mW values + data.power = (float) wiringPiI2CReadReg16(sensor.fd, INA219_REG_POWER) * (float) sensor.powerMultiplier; + + return data; +} + +/** + * @brief Configures an i2c current sensor. + * + * Calculates the configuration values of the i2c sensor so that + * current, voltage, and power can be read using read_sensor_data. + * Supports 16V 400mA and 16V 2.0A settings. + * + * @param sensor A file descriptor that can be used to read from the sensor. + * @param milliAmps The mA configuration, either 400mA or 2A are supported. + * @return struct SensorConfig A struct that contains the configuraton of the sensor. + */ +//struct SensorConfig config_sensor(int sensor, int milliAmps) { +struct SensorConfig config_sensor(char *bus, int address, int milliAmps) { + struct SensorConfig data; + + if (access(bus, W_OK | R_OK) < 0) { // Test if I2C Bus is missing + printf("ERROR: %s bus not present \n", bus); + data.fd = OFF; + return (data); + } + + data.fd = wiringPiI2CSetupInterface(bus, address); + + data.config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_1_40MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_1S_532US | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + if (milliAmps == 400) { // INA219 16V 400mA configuration + data.calValue = 8192; + data.powerMultiplier = 1; + data.currentDivider = 20; // 40; in Adafruit config + } + else { // INA219 16V 2A configuration + data.calValue = 40960; + data.powerMultiplier = 2; + data.currentDivider = 10; // 20; in Adafruit config + } + + #ifdef DEBUG_LOGGING + printf("Sensor %s %x configuration: %d %d %d %d %d\n", bus, address, data.fd, + data.config, data.calValue, data.currentDivider, data.powerMultiplier); + #endif + return data; +} + +struct SensorConfig sensor[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorData reading[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorConfig tempSensor; + +char src_addr[5] = ""; +char dest_addr[5] = "CQ"; + +int main(int argc, char *argv[]) { + + if (argc > 1) { + strcpy(src_addr, argv[1]); + } + + wiringPiSetup (); + pinMode (0, OUTPUT); + + //setSpiChannel(SPI_CHANNEL); + //setSpiSpeed(SPI_SPEED); + //initializeSpi(); + + FILE* config_file = fopen("sim.cfg","r"); + if (config_file == NULL) + { + printf("Creating config file."); + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", "KU2Y", 100); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + } + + char* cfg_buf[100]; + fscanf(config_file, "%s %d", call, &reset_count); + fclose(config_file); + printf("%s %d\n", call, reset_count); + + reset_count = (reset_count + 1) % 0xffff; + + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", call, reset_count); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + + tempSensor = config_sensor("/dev/i2c-3", 0x48, 0); + + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); + + int ret; + uint8_t data[1024]; + + tx_freq_hz -= tx_channel * 50000; + + //init_rf(); + + ax25_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) src_addr, '1', + AX25_PREAMBLE_LEN, + AX25_POSTAMBLE_LEN); + + /* Infinite loop */ + //for (;;) + + { + // sleep(1); // Delay 1 second + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting TLM Data\n"); + #endif + + char str[1000]; + // uint8_t b[64]; + char header_str[] = "\x03\xf0"; + strcpy(str, header_str); + + printf("%s-1>%s-1:", (uint8_t *)src_addr, (uint8_t *)dest_addr); + +// get_tlm(str); + get_tlm_fox(); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting ready to send\n"); + #endif + + char cmdbuffer[1000]; + FILE* transmit; + if (DUV == 1) { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/CubeSatSim/rpitx/rpitx -i- -m RF -f 434.9e3 2>&1", "r"); + } else { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr fir_interpolate_cc 2 | csdr dsb_fc | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff | sudo /home/pi/CubeSatSim/rpitx/sendiq -i /dev/stdin -s 96000 -f 434.9e6 -t float 2>&1", "r"); + } + fgets(cmdbuffer, 1000, transmit); + pclose(transmit); + printf("Results of transmit command: %s\n", cmdbuffer); + + + +// printf("%s \n", b); +/* + digitalWrite (0, LOW); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Transmitting X.25 packet\n"); + #endif + memcpy(data, str, strnlen(str, 256)); + ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } + + ax5043_wait_for_transmit(); + + digitalWrite (0, HIGH); + + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } +*/ + } + + return 0; +} + +static void init_rf() { + int ret; + #ifdef DEBUG_LOGGING + fprintf(stderr,"Initializing AX5043\n"); + #endif + ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); + if (ret != PQWS_SUCCESS) { + fprintf(stderr, + "ERROR: Failed to initialize AX5043 with error code %d\n", ret); + exit(EXIT_FAILURE); + } +} + +// Returns lower digit of a number which must be less than 99 +// +int lower_digit(int number) { + + int digit = 0; + if (number < 100) + digit = number - ((int)(number/10) * 10); + else + fprintf(stderr,"ERROR: Not a digit in lower_digit!\n"); + return digit; +} + +// Returns upper digit of a number which must be less than 99 +// +int upper_digit(int number) { + + int digit = 0; + if (number < 100) + digit = (int)(number/10); + else + fprintf(stderr,"ERROR: Not a digit in upper_digit!\n"); + return digit; +} + +int get_tlm(char *str) { + + int tlm[7][5]; + memset(tlm, 0, sizeof tlm); + +// Reading I2C voltage and current sensors + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } + + tlm[1][A] = (int)(reading[BUS].voltage /15.0 + 0.5) % 100; // Current of 5V supply to Pi + tlm[1][B] = (int) (99.5 - reading[PLUS_X].current/10.0) % 100; // +X current [4] + tlm[1][C] = (int) (99.5 - reading[MINUS_X].current/10.0) % 100; // X- current [10] + tlm[1][D] = (int) (99.5 - reading[PLUS_Y].current/10.0) % 100; // +Y current [7] + + tlm[2][A] = (int) (99.5 - reading[MINUS_Y].current/10.0) % 100; // -Y current [10] + tlm[2][B] = (int) (99.5 - reading[PLUS_Z].current/10.0) % 100; // +Z current [10] // was 70/2m transponder power, AO-7 didn't have a Z panel + tlm[2][C] = (int) (99.5 - reading[MINUS_Z].current/10.0) % 100; // -Z current (was timestamp) + tlm[2][D] = (int)(50.5 + reading[BAT].current/10.0) % 100; // NiMH Battery current + + tlm[3][A] = abs((int)((reading[BAT].voltage * 10.0) - 65.5) % 100); + tlm[3][B] = (int)(reading[BUS].voltage * 10.0) % 100; // 5V supply to Pi + + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + tlm[4][A] = (int)((95.8 - temp)/1.48 + 0.5) % 100; + } + + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + tlm[4][B] = (int)((95.8 - cpuTemp)/1.48 + 0.5) % 100; + fclose (cpuTempSensor); + } + + tlm[6][B] = 0 ; + tlm[6][D] = 49 + rand() % 3; + + #ifdef DEBUG_LOGGING +// Display tlm + int k, j; + for (k = 1; k < 7; k++) { + for (j = 1; j < 5; j++) { + printf(" %2d ", tlm[k][j]); + } + printf("\n"); + } + #endif + + char tlm_str[1000]; + + char header_str[] = "hi hi "; + strcpy(str, header_str); +// printf("%s-1>%s-1:hi hi ", (uint8_t *)src_addr, (uint8_t *)dest_addr); + + int channel; + for (channel = 1; channel < 7; channel++) { + sprintf(tlm_str, "%d%d%d %d%d%d %d%d%d %d%d%d ", + channel, upper_digit(tlm[channel][1]), lower_digit(tlm[channel][1]), + channel, upper_digit(tlm[channel][2]), lower_digit(tlm[channel][2]), + channel, upper_digit(tlm[channel][3]), lower_digit(tlm[channel][3]), + channel, upper_digit(tlm[channel][4]), lower_digit(tlm[channel][4])); +// printf("%s",tlm_str); + strcat(str, tlm_str); + } +// printf("\n"); + +return; +} + +int get_tlm_fox() { + +// memset(b, 0, 64); + +// Reading I2C voltage and current sensors + + FILE* uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + fclose(uptime_file); + + int i; + long int sync = SYNC_WORD; + + smaller = S_RATE/(2 * freq_Hz); +/* + short int b[DATA_LEN] = {0x00,0x7E,0x03, + 0x00,0x00,0x00,0x00,0xE6,0x01,0x00,0x27,0xD1,0x02, + 0xE5,0x40,0x04,0x18,0xE1,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + short int h[HEADER_LEN] = {0x05,0x00,0x00,0x00,0x00,0x10,0x00,0x00}; +*/ + + short int b[DATA_LEN]; + memset(b, 0, sizeof(b)); + + short int h[HEADER_LEN]; + memset(h, 0, sizeof(h)); + + short int b10[DATA_LEN], h10[HEADER_LEN]; + short int rs_frame[RS_FRAMES][223]; + unsigned char parities[RS_FRAMES][PARITY_LEN],inputByte; +/* + int id = 5, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 8.95 * 100, battCurr = 48.6 * 10; + int posXv = 296, negXv = 45, posYv = 220, negYv = 68, + posZv = 280, negZv = 78; +*/ + int id = 5, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 0, battCurr = 0; + int posXv = 0, negXv = 0, posYv = 0, negYv = 0, + posZv = 0, negZv = 0; + int head_offset = 0; + + for (int frames = 0; frames < FRAME_CNT; frames++) + { + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } +/* + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + TxTemp = (int)((temp * 10.0) + 0.5); + encodeB(b, 34 + head_offset, TxTemp); + } +*/ + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + IHUcpuTemp = (int)((cpuTemp * 10.0) + 0.5); + encodeA(b, 39 + head_offset, IHUcpuTemp); + } + sleep(1); + + memset(rs_frame,0,sizeof(rs_frame)); + memset(parities,0,sizeof(parities)); + + FILE *uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + fclose(uptime_file); + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + + h[0] = (h[0] & 0xf8) | (id & 0x07); // 3 bits + printf("h[0] %x\n", h[0]); + h[0] = (h[0] & 0x07)| ((reset_count & 0x1f) << 3); + printf("h[0] %x\n", h[0]); + h[1] = (reset_count >> 5) & 0xff; + printf("h[1] %x\n", h[1]); + h[2] = (h[2] & 0xf8) | ((reset_count >> 13) & 0x07); + printf("h[2] %x\n", h[2]); + h[2] = (h[2] & 0x0e) | ((uptime & 0x1f) << 3); + printf("h[2] %x\n", h[2]); + h[3] = (uptime >> 5) & 0xff; + h[4] = (uptime >> 13) & 0xff; + h[5] = (h[5] & 0xf0) | ((uptime >> 21) & 0x0f); + h[5] = (h[5] & 0x0f) | (frm_type << 4); + + posXv = reading[PLUS_X].current * 10; + posYv = reading[PLUS_Y].current * 10; + posZv = reading[PLUS_Z].current * 10; + negXv = reading[MINUS_X].current * 10; + negYv = reading[MINUS_Y].current * 10; + negZv = reading[MINUS_Z].current * 10; + + batt_c_v = reading[BAT].voltage * 100; + battCurr = reading[BAT].current * 10; + + encodeA(b, 0 + head_offset, batt_a_v); + encodeB(b, 1 + head_offset, batt_b_v); + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); + encodeA(b, 12 + head_offset,posXv); + encodeB(b, 13 + head_offset,posYv); + encodeA(b, 15 + head_offset,posZv); + encodeB(b, 16 + head_offset,negXv); + encodeA(b, 18 + head_offset,negYv); + encodeB(b, 19 + head_offset,negZv); + +/* batt_c_v += 10; + battCurr -= 10; + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); +*/ + int ctr1 = 0; + int ctr3 = 0; + for (i = 0; i < RS_FRAME_LEN; i++) + { + for (int j = 0; j < RS_FRAMES ; j++) + { + if (!((i == (RS_FRAME_LEN - 1)) && (j == 2))) // skip last one for BPSK + { + if (ctr1 < HEADER_LEN) + { + rs_frame[j][i] = h[ctr1]; + update_rs(parities[j], h[ctr1]); + // printf("header %d rs_frame[%d][%d] = %x \n", ctr1, j, i, h[ctr1]); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + } + else + { + rs_frame[j][i] = b[ctr3 % DATA_LEN]; + update_rs(parities[j], b[ctr3 % DATA_LEN]); + // printf("%d rs_frame[%d][%d] = %x %d \n", + // ctr1, j, i, b[ctr3 % DATA_LEN], ctr3 % DATA_LEN); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + ctr3++; + } + } + } + } + + printf("Parities "); + for (int m = 0; m < PARITY_LEN; m++) { + printf("%d ", parities[0][m]); + } + printf("\n"); + + int ctr2 = 0; + memset(data10,0,sizeof(data10)); + int rd = 0; + int nrd; + + for (i = 0; i < DATA_LEN * PAYLOADS + HEADER_LEN; i++) // 476 for BPSK + { + data10[ctr2] = (Encode_8b10b[rd][((int)data8[ctr2])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)data8[ctr2])] >> 10) & 1; + // printf ("data10[%d] = encoded data8[%d] = %x \n", + // ctr2, ctr2, data10[ctr2]); + + rd = nrd; // ^ nrd; + ctr2++; + } + + for (i = 0; i < PARITY_LEN; i++) + { + for (int j = 0; j < RS_FRAMES; j++) + { + data10[ctr2++] = (Encode_8b10b[rd][((int)parities[j][i])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)parities[j][i])] >> 10) & 1; + // printf ("data10[%d] = encoded parities[%d][%d] = %x \n", + // ctr2 - 1, j, i, data10[ctr2 - 1]); + + rd = nrd; + } + } + + int data; + int val; + int offset = 0; + + for (i = 1; i <= SYNC_BITS * SAMPLES; i++) + { + write_wave(ctr); + if ( (i % SAMPLES) == 0) { + int bit = SYNC_BITS - i/SAMPLES + 1; + val = sync; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d sync bit %d = %d \n", + // ctr/SAMPLES, i, frames, bit, (data > 0) ); + if (DUV) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + + for (i = 1; + i <= (10 * (HEADER_LEN + DATA_LEN * PAYLOADS + RS_FRAMES * PARITY_LEN) * SAMPLES); i++) // 572 + { + write_wave(ctr); + if ( (i % SAMPLES) == 0) { + int symbol = (int)((i - 1)/ (SAMPLES * 10)); + int bit = 10 - (i - symbol * SAMPLES * 10) / SAMPLES + 1; + val = data10[symbol]; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d data10[%d] = %x bit %d = %d \n", + // ctr/SAMPLES, i, frames, symbol, val, bit, (data > 0) ); + if (DUV) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j ++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + } + write_wav("transmit.wav", BUF_LEN, buffer, S_RATE); + + int count; + for (count = 0; count < DATA_LEN; count++) { + printf("%02X", b[count]); + } + printf("\n"); + +return 0; +} + +// wav file generation code + +/* make_wav.c + * Creates a WAV file from an array of ints. + * Output is monophonic, signed 16-bit samples + * copyright + * Fri Jun 18 16:36:23 PDT 2010 Kevin Karplus + * Creative Commons license Attribution-NonCommercial + * http://creativecommons.org/licenses/by-nc/3.0/ + * + * Edited by Dolin Sergey. dlinyj@gmail.com + * April 11 12:58 2014 + */ + + // gcc -o make_enc_wav make_enc_wav.c -lm + // ./make_enc_wav + + /* + * TelemEncoding.h + * + * Created on: Feb 3, 2014 + * Author: fox + */ + +#include +#include +#include +#include +#include +#include + +//#include "make_wav.h" + +#define false 0 +#define true 1 + +//static int twosToInt(int val,int len); +//static int encodeB(short int *b, int index, int val); +//static int encodeA(short int *b, int index, int val); + + static int NOT_FRAME = /* 0fa */ 0xfa & 0x3ff; + static int FRAME = /* 0fa */ ~0xfa & 0x3ff; + +/* + * TelemEncoding.c + * + Fox-1 telemetry encoder + January 2014 Phil Karn KA9Q + + This file has two external functions: + void update_rs(unsigned char parity[32],unsigned char data); + int encode_8b10b(int *state,int data). + + update_rs() is the Reed-Solomon encoder. Its first argument is the 32-byte + encoder shift register, the second is the 8-bit data byte being encoded. It updates + the shift register in place and returns void. At the end of each frame, it contains + the parities ready for transmission, starting with parity[0]. + Be sure to zero this array before each new frame! + + encode_8b10b() is the 8b10b encoder. Its first argument is a pointer to a single integer + with the 1-bit encoder state (the current run disparity, or RD). Initialize it to 0 + JUST ONCE at startup (not between frames). + The second argument is the data byte being encoded. It updates the state and returns + an integer containing the 10-bit encoded word, right justified. + Transmit this word from left to right. + + The data argument is an int so it can hold the special value -1 to indicate end of frame; + it generates the 8b10b control word K.28.5, which is used as an inter-frame flag. + + Some assert() calls are made to verify legality of arguments. These can be turned off in + production code. + + + sample frame transmission code: + + unsigned char data[64]; // Data block to be sent + unsigned char parity[32]; // RS parities + void transmit_word(int); // User provided transmit function: 10 bits of data in bits 9....0 + int state,i; + + state = 0; // Only once at startup, not between frames + memset(parity,0,sizeof(parity); // Do this before every frame + // Transmit the data, updating the RS encoder + for(i=0;i<64;i++){ + update_rs(parity,data[i]); + transmit_word(encode_8b10b(&state,data[i]); + } + // Transmit the RS parities + for(i=0;i<32;i++) + transmit_word(encode_8b10b(&state,parity[i]); + + transmit_word(encode_8b10b(&state,-1); // Transmit end-of-frame flag +*/ + + +#include +//#include "Fox.h" +//#include "TelemEncoding.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define NN (0xff) // Frame size in symbols +#define A0 (NN) // special value for log(0) + + +// GF Antilog lookup table table +static unsigned char CCSDS_alpha_to[NN+1] = { +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, +0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, +0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, +0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, +0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, +0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, +0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, +0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, +0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, +0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, +0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, +0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, +0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, +0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, +0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, +0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, +}; + +// GF log lookup table. Special value represents log(0) +static unsigned char CCSDS_index_of[NN+1] = { + A0, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, + 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, + 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, +103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, + 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, +202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, +104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, +110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, + 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, +209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, +203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, +192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, +105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, +130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, +111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, + 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, +}; + +// Only half the coefficients are given here because the +// generator polynomial is palindromic; G0 = G32, G1 = G31, etc. +// Only G16 is unique +static unsigned char CCSDS_poly[] = { + 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, + 24, +}; + + +static inline int modnn(int x){ + while (x >= NN) { + x -= NN; + x = (x >> 8) + (x & NN); + } + return x; +} + + +// Update Reed-Solomon encoder +// parity -> 32-byte reed-solomon encoder state; clear this to zero before each frame +void update_rs( + unsigned char parity[32], // 32-byte encoder state; zero before each frame + unsigned char c) // Current data byte to update +{ + unsigned char feedback; + int j,t; + + assert(parity != NULL); + feedback = CCSDS_index_of[c ^ parity[0]]; + if(feedback != A0){ // only if feedback is non-zero + // Take advantage of palindromic polynomial to halve the multiplies + // Do G1...G15, which is the same as G17...G31 + for(j=1;j0) + { buf = word & 0xff; + fwrite(&buf, 1,1, wav_file); + num_bytes--; + word >>= 8; + } +} + +/* information about the WAV file format from + +http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ + + */ + +void write_wav(char * filename, unsigned long num_samples, short int * data, int s_rate) +{ + FILE* wav_file; + unsigned int sample_rate; + unsigned int num_channels; + unsigned int bytes_per_sample; + unsigned int byte_rate; + unsigned long i; /* counter for samples */ + + num_channels = 1; /* monoaural */ + bytes_per_sample = 2; + + if (s_rate<=0) sample_rate = 44100; + else sample_rate = (unsigned int) s_rate; + + byte_rate = sample_rate*num_channels*bytes_per_sample; + + wav_file = fopen(filename, "w"); + assert(wav_file); /* make sure it opened */ + + /* write RIFF header */ + fwrite("RIFF", 1, 4, wav_file); + write_little_endian(36 + bytes_per_sample* num_samples*num_channels, 4, wav_file); + fwrite("WAVE", 1, 4, wav_file); + + /* write fmt subchunk */ + fwrite("fmt ", 1, 4, wav_file); + write_little_endian(16, 4, wav_file); /* SubChunk1Size is 16 */ + write_little_endian(1, 2, wav_file); /* PCM is format 1 */ + write_little_endian(num_channels, 2, wav_file); + write_little_endian(sample_rate, 4, wav_file); + write_little_endian(byte_rate, 4, wav_file); + write_little_endian(num_channels*bytes_per_sample, 2, wav_file); /* block align */ + write_little_endian(8*bytes_per_sample, 2, wav_file); /* bits/sample */ + + /* write data subchunk */ + fwrite("data", 1, 4, wav_file); + write_little_endian(bytes_per_sample* num_samples*num_channels, 4, wav_file); + + for (i=0; i< num_samples; i++) + { write_little_endian((unsigned int)(data[i]),bytes_per_sample, wav_file); + } + + fclose(wav_file); +} + + + +//int main(int argc, char * argv[]) +//{ + +// return 0; +//} + +void write_wave(int i) +{ + if (DUV) + { +// if ((ctr - flip_ctr) < smaller) +// buffer[ctr++] = 0.1 * phase * (ctr - flip_ctr) / smaller; +// else + buffer[ctr++] = 0.25 * amplitude * phase; + } + else + { + if ((ctr - flip_ctr) < smaller) + buffer[ctr++] = (int)(amplitude * 0.4 * phase * + sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + else + buffer[ctr++] = (int)(amplitude * phase * + sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + } +// printf("%d %d \n", i, buffer[ctr - 1]); + +} + +/** + * + * FOX 1 Telemetry Decoder + * @author chris.e.thompson g0kla/ac2cz + * + * Copyright (C) 2015 amsat.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General 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 License for more details. + * + * You should have received a copy of the GNU General License + * along with this program. If not, see . + * + * + * Static variables and methods to encode and decode 8b10b + * + * + */ + +int encodeA(short int *b, int index, int val) { +// printf("Encoding A\n"); + b[index] = val & 0xff; + b[index + 1] = (b[index + 1] & 0xf0) | ((val >> 8) & 0x0f); + return 0; +} + +int encodeB(short int *b, int index, int val) { +// printf("Encoding B\n"); + b[index] = (b[index] & 0x0f) | ((val << 4) & 0xf0); + b[index + 1] = (val >> 4 ) & 0xff; + return 0; +} + +int twosToInt(int val,int len) { // Convert twos compliment to integer +// from https://www.raspberrypi.org/forums/viewtopic.php?t=55815 + + if(val & (1 << (len - 1))) + val = val - (1 << len); + + return(val); +} diff --git a/afsk/main_memcpy.c b/afsk/main_memcpy.c new file mode 100644 index 00000000..fc935697 --- /dev/null +++ b/afsk/main_memcpy.c @@ -0,0 +1,1128 @@ +/* + * Transmits CubeSat Telemetry at 434.9MHz in AO-7 format + * + * Copyright Alan B. Johnston + * + * Portions Copyright (C) 2018 Jonathan Brandenburg + * + * 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 . + * + * INA219 Raspberry Pi wiringPi code is based on Adafruit Arduino wire codeF + * from https://github.com/adafruit/Adafruit_INA219. + */ + +#include +#include +#include +#include +#include +#include "status.h" +#include "ax5043.h" +#include "ax25.h" +#include "spi/ax5043spi.h" +#include +#include +#include +#include +#include "Adafruit_INA219.h" // From Adafruit INA219 library for Arduino +#include "make_wav.h" + +#define A 1 +#define B 2 +#define C 3 +#define D 4 + +#define PLUS_X 0 +#define PLUS_Y 1 +#define PLUS_Z 2 +#define BAT 3 +#define MINUS_X 4 +#define MINUS_Y 5 +#define MINUS_Z 6 +#define BUS 7 +#define OFF -1 + +uint32_t tx_freq_hz = 434900000 + FREQUENCY_OFFSET; +uint32_t tx_channel = 0; + +ax5043_conf_t hax5043; +ax25_conf_t hax25; + +static void init_rf(); +int twosToInt(int val, int len); +int get_tlm(char *str); +int get_tlm_fox(); +int encodeA(short int *b, int index, int val); +int encodeB(short int *b, int index, int val); +void config_x25(); +void trans_x25(); +int upper_digit(int number); +int lower_digit(int number); + +#define S_RATE (48000) // (44100) +#define BUF_SIZE (S_RATE*10) /* 2 second buffer */ + +// BPSK Settings +#define BIT_RATE 1200 // 200 for DUV +#define DUV 0 // 1 for DUV +#define RS_FRAMES 3 // 3 frames for BPSK, 1 for DUV +#define PAYLOADS 6 // 1 for DUV +#define DATA_LEN 78 // 56 for DUV +#define RS_FRAME_LEN 159 // 64 for DUV +#define SYNC_BITS 31 // 10 for DUV +#define SYNC_WORD 0b1000111110011010010000101011101 // 0b0011111010 for DUV +#define HEADER_LEN 8 // 6 for DUV +/* +// DUV Settings +#define BIT_RATE 200 +#define DUV 1 +#define RS_FRAMES 1 +#define PAYLOADS 1 +#define RS_FRAME_LEN 64 +#define HEADER_LEN 6 +#define DATA_LEN 58 +#define SYNC_BITS 10 +#define SYNC_WORD 0b0011111010 +*/ + +#define PARITY_LEN 32 + +float amplitude = 32767/3; // 20000; // 32767/(10%amp+5%amp+100%amp) +float freq_Hz = 3000; // 1200 + +int smaller; +int flip_ctr = 0; +int phase = 1; +int ctr = 0; +long int ptr = 0; + +void copy_samples(); +void write_to_buffer(int i, int symbol, int val); +void write_wave(); +#define SAMPLES (S_RATE / BIT_RATE) +#define FRAME_CNT 33 // Add 3 frames to the count + +//#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (8 + 6 * DATA_LEN + 96)) * SAMPLES) +#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN))) * SAMPLES) +short int buffer[BUF_LEN]; +short int phase0[SAMPLES], phase1[SAMPLES]; +int size_of_phase; +short int data10[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +short int data8[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +int reset_count; +float uptime_sec; +long int uptime; +char call[5]; + +struct SensorConfig { + int fd; + uint16_t config; + int calValue; + int powerMultiplier; + int currentDivider; +}; + +struct SensorData { + double current; + double voltage; + double power; +}; + +/** + * @brief Read the data from one of the i2c current sensors. + * + * Reads the current data from the requested i2c current sensor configuration and + * stores it into a SensorData struct. An invalid file descriptor (i.e. less than zero) + * results in a SensorData struct being returned that has both its #current and #power members + * set to NAN. + * + * @param sensor A structure containing sensor configuration including the file descriptor. + * @return struct SensorData A struct that contains the current, voltage, and power readings + * from the requested sensor. + */ +struct SensorData read_sensor_data(struct SensorConfig sensor) { + struct SensorData data = { + .current = NAN, + .voltage = NAN, + .power = NAN }; + + if (sensor.fd < 0) { + return data; + } + // doesn't read negative currents accurately, shows -0.1mA + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CONFIG, sensor.config); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + int value = wiringPiI2CReadReg16(sensor.fd, INA219_REG_CURRENT); + data.current = (float) twosToInt(value, 16) / (float) sensor.currentDivider; + + wiringPiI2CWrite(sensor.fd, INA219_REG_BUSVOLTAGE); + delay(1); // Max 12-bit conversion time is 586us per sample + value = (wiringPiI2CRead(sensor.fd) << 8 ) | wiringPiI2CRead (sensor.fd); + data.voltage = ((float)(value >> 3) * 4) / 1000; + // power has very low resolution, seems to step in 512mW values + data.power = (float) wiringPiI2CReadReg16(sensor.fd, INA219_REG_POWER) * (float) sensor.powerMultiplier; + + return data; +} + +/** + * @brief Configures an i2c current sensor. + * + * Calculates the configuration values of the i2c sensor so that + * current, voltage, and power can be read using read_sensor_data. + * Supports 16V 400mA and 16V 2.0A settings. + * + * @param sensor A file descriptor that can be used to read from the sensor. + * @param milliAmps The mA configuration, either 400mA or 2A are supported. + * @return struct SensorConfig A struct that contains the configuraton of the sensor. + */ +//struct SensorConfig config_sensor(int sensor, int milliAmps) { +struct SensorConfig config_sensor(char *bus, int address, int milliAmps) { + struct SensorConfig data; + + if (access(bus, W_OK | R_OK) < 0) { // Test if I2C Bus is missing + printf("ERROR: %s bus not present \n", bus); + data.fd = OFF; + return (data); + } + + data.fd = wiringPiI2CSetupInterface(bus, address); + + data.config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_1_40MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_1S_532US | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + if (milliAmps == 400) { // INA219 16V 400mA configuration + data.calValue = 8192; + data.powerMultiplier = 1; + data.currentDivider = 20; // 40; in Adafruit config + } + else { // INA219 16V 2A configuration + data.calValue = 40960; + data.powerMultiplier = 2; + data.currentDivider = 10; // 20; in Adafruit config + } + + #ifdef DEBUG_LOGGING + printf("Sensor %s %x configuration: %d %d %d %d %d\n", bus, address, data.fd, + data.config, data.calValue, data.currentDivider, data.powerMultiplier); + #endif + return data; +} + +struct SensorConfig sensor[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorData reading[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorConfig tempSensor; + +char src_addr[5] = ""; +char dest_addr[5] = "CQ"; + +int main(int argc, char *argv[]) { + + if (argc > 1) { + strcpy(src_addr, argv[1]); + } + + wiringPiSetup (); + pinMode (0, OUTPUT); + + //setSpiChannel(SPI_CHANNEL); + //setSpiSpeed(SPI_SPEED); + //initializeSpi(); + + FILE* config_file = fopen("sim.cfg","r"); + if (config_file == NULL) + { + printf("Creating config file."); + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", "KU2Y", 100); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + } + + char* cfg_buf[100]; + fscanf(config_file, "%s %d", call, &reset_count); + fclose(config_file); + printf("%s %d\n", call, reset_count); + + reset_count = (reset_count + 1) % 0xffff; + + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", call, reset_count); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + + tempSensor = config_sensor("/dev/i2c-3", 0x48, 0); + + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); + + int ret; + uint8_t data[1024]; + + tx_freq_hz -= tx_channel * 50000; + + //init_rf(); + + ax25_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) src_addr, '1', + AX25_PREAMBLE_LEN, + AX25_POSTAMBLE_LEN); + + ptr = 0; + size_of_phase = sizeof(phase0); + int j; + phase = 1; + for (j = 0; j < SAMPLES; j++) + { + write_wave(j, phase1); + } + phase = -1; + for (j = 0; j < SAMPLES; j++) + { + write_wave(j, phase0); + } + + + /* Infinite loop */ + //for (;;) + + { + // sleep(1); // Delay 1 second + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting TLM Data\n"); + #endif + + char str[1000]; + // uint8_t b[64]; + char header_str[] = "\x03\xf0"; + strcpy(str, header_str); + + printf("%s-1>%s-1:", (uint8_t *)src_addr, (uint8_t *)dest_addr); + +// get_tlm(str); + get_tlm_fox(); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting ready to send\n"); + #endif + + char cmdbuffer[1000]; + FILE* transmit; + if (DUV == 1) { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/CubeSatSim/rpitx/rpitx -i- -m RF -f 434.9e3 2>&1", "r"); + } else { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr fir_interpolate_cc 2 | csdr dsb_fc | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff | sudo /home/pi/CubeSatSim/rpitx/sendiq -i /dev/stdin -s 96000 -f 434.9e6 -t float 2>&1", "r"); + } + fgets(cmdbuffer, 1000, transmit); + pclose(transmit); + printf("Results of transmit command: %s\n", cmdbuffer); + + + +// printf("%s \n", b); +/* + digitalWrite (0, LOW); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Transmitting X.25 packet\n"); + #endif + memcpy(data, str, strnlen(str, 256)); + ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } + + ax5043_wait_for_transmit(); + + digitalWrite (0, HIGH); + + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } +*/ + } + + return 0; +} + +static void init_rf() { + int ret; + #ifdef DEBUG_LOGGING + fprintf(stderr,"Initializing AX5043\n"); + #endif + ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); + if (ret != PQWS_SUCCESS) { + fprintf(stderr, + "ERROR: Failed to initialize AX5043 with error code %d\n", ret); + exit(EXIT_FAILURE); + } +} + +// Returns lower digit of a number which must be less than 99 +// +int lower_digit(int number) { + + int digit = 0; + if (number < 100) + digit = number - ((int)(number/10) * 10); + else + fprintf(stderr,"ERROR: Not a digit in lower_digit!\n"); + return digit; +} + +// Returns upper digit of a number which must be less than 99 +// +int upper_digit(int number) { + + int digit = 0; + if (number < 100) + digit = (int)(number/10); + else + fprintf(stderr,"ERROR: Not a digit in upper_digit!\n"); + return digit; +} + +int get_tlm(char *str) { + + int tlm[7][5]; + memset(tlm, 0, sizeof tlm); + +// Reading I2C voltage and current sensors + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } + + tlm[1][A] = (int)(reading[BUS].voltage /15.0 + 0.5) % 100; // Current of 5V supply to Pi + tlm[1][B] = (int) (99.5 - reading[PLUS_X].current/10.0) % 100; // +X current [4] + tlm[1][C] = (int) (99.5 - reading[MINUS_X].current/10.0) % 100; // X- current [10] + tlm[1][D] = (int) (99.5 - reading[PLUS_Y].current/10.0) % 100; // +Y current [7] + + tlm[2][A] = (int) (99.5 - reading[MINUS_Y].current/10.0) % 100; // -Y current [10] + tlm[2][B] = (int) (99.5 - reading[PLUS_Z].current/10.0) % 100; // +Z current [10] // was 70/2m transponder power, AO-7 didn't have a Z panel + tlm[2][C] = (int) (99.5 - reading[MINUS_Z].current/10.0) % 100; // -Z current (was timestamp) + tlm[2][D] = (int)(50.5 + reading[BAT].current/10.0) % 100; // NiMH Battery current + + tlm[3][A] = abs((int)((reading[BAT].voltage * 10.0) - 65.5) % 100); + tlm[3][B] = (int)(reading[BUS].voltage * 10.0) % 100; // 5V supply to Pi + + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + tlm[4][A] = (int)((95.8 - temp)/1.48 + 0.5) % 100; + } + + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + tlm[4][B] = (int)((95.8 - cpuTemp)/1.48 + 0.5) % 100; + fclose (cpuTempSensor); + } + + tlm[6][B] = 0 ; + tlm[6][D] = 49 + rand() % 3; + + #ifdef DEBUG_LOGGING +// Display tlm + int k, j; + for (k = 1; k < 7; k++) { + for (j = 1; j < 5; j++) { + printf(" %2d ", tlm[k][j]); + } + printf("\n"); + } + #endif + + char tlm_str[1000]; + + char header_str[] = "hi hi "; + strcpy(str, header_str); +// printf("%s-1>%s-1:hi hi ", (uint8_t *)src_addr, (uint8_t *)dest_addr); + + int channel; + for (channel = 1; channel < 7; channel++) { + sprintf(tlm_str, "%d%d%d %d%d%d %d%d%d %d%d%d ", + channel, upper_digit(tlm[channel][1]), lower_digit(tlm[channel][1]), + channel, upper_digit(tlm[channel][2]), lower_digit(tlm[channel][2]), + channel, upper_digit(tlm[channel][3]), lower_digit(tlm[channel][3]), + channel, upper_digit(tlm[channel][4]), lower_digit(tlm[channel][4])); +// printf("%s",tlm_str); + strcat(str, tlm_str); + } +// printf("\n"); + +return; +} + +int get_tlm_fox() { + +// memset(b, 0, 64); + +// Reading I2C voltage and current sensors + + FILE* uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + fclose(uptime_file); + + int i; + long int sync = SYNC_WORD; + + smaller = S_RATE/(2 * freq_Hz); +/* + short int b[DATA_LEN] = {0x00,0x7E,0x03, + 0x00,0x00,0x00,0x00,0xE6,0x01,0x00,0x27,0xD1,0x02, + 0xE5,0x40,0x04,0x18,0xE1,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + short int h[HEADER_LEN] = {0x05,0x00,0x00,0x00,0x00,0x10,0x00,0x00}; +*/ + + short int b[DATA_LEN]; + memset(b, 0, sizeof(b)); + + short int h[HEADER_LEN]; + memset(h, 0, sizeof(h)); + + short int b10[DATA_LEN], h10[HEADER_LEN]; + short int rs_frame[RS_FRAMES][223]; + unsigned char parities[RS_FRAMES][PARITY_LEN],inputByte; +/* + int id = 5, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 8.95 * 100, battCurr = 48.6 * 10; + int posXv = 296, negXv = 45, posYv = 220, negYv = 68, + posZv = 280, negZv = 78; +*/ + int id = 5, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 0, battCurr = 0; + int posXv = 0, negXv = 0, posYv = 0, negYv = 0, + posZv = 0, negZv = 0; + int head_offset = 0; + + for (int frames = 0; frames < FRAME_CNT; frames++) + { + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } +/* + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + TxTemp = (int)((temp * 10.0) + 0.5); + encodeB(b, 34 + head_offset, TxTemp); + } +*/ + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + IHUcpuTemp = (int)((cpuTemp * 10.0) + 0.5); + encodeA(b, 39 + head_offset, IHUcpuTemp); + } + sleep(1); + + memset(rs_frame,0,sizeof(rs_frame)); + memset(parities,0,sizeof(parities)); + + FILE *uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + fclose(uptime_file); + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + + h[0] = (h[0] & 0xf8) | (id & 0x07); // 3 bits + printf("h[0] %x\n", h[0]); + h[0] = (h[0] & 0x07)| ((reset_count & 0x1f) << 3); + printf("h[0] %x\n", h[0]); + h[1] = (reset_count >> 5) & 0xff; + printf("h[1] %x\n", h[1]); + h[2] = (h[2] & 0xf8) | ((reset_count >> 13) & 0x07); + printf("h[2] %x\n", h[2]); + h[2] = (h[2] & 0x0e) | ((uptime & 0x1f) << 3); + printf("h[2] %x\n", h[2]); + h[3] = (uptime >> 5) & 0xff; + h[4] = (uptime >> 13) & 0xff; + h[5] = (h[5] & 0xf0) | ((uptime >> 21) & 0x0f); + h[5] = (h[5] & 0x0f) | (frm_type << 4); + + posXv = reading[PLUS_X].current * 10; + posYv = reading[PLUS_Y].current * 10; + posZv = reading[PLUS_Z].current * 10; + negXv = reading[MINUS_X].current * 10; + negYv = reading[MINUS_Y].current * 10; + negZv = reading[MINUS_Z].current * 10; + + batt_c_v = reading[BAT].voltage * 100; + battCurr = reading[BAT].current * 10; + + encodeA(b, 0 + head_offset, batt_a_v); + encodeB(b, 1 + head_offset, batt_b_v); + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); + encodeA(b, 12 + head_offset,posXv); + encodeB(b, 13 + head_offset,posYv); + encodeA(b, 15 + head_offset,posZv); + encodeB(b, 16 + head_offset,negXv); + encodeA(b, 18 + head_offset,negYv); + encodeB(b, 19 + head_offset,negZv); + +/* batt_c_v += 10; + battCurr -= 10; + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); +*/ + int ctr1 = 0; + int ctr3 = 0; + for (i = 0; i < RS_FRAME_LEN; i++) + { + for (int j = 0; j < RS_FRAMES ; j++) + { + if (!((i == (RS_FRAME_LEN - 1)) && (j == 2))) // skip last one for BPSK + { + if (ctr1 < HEADER_LEN) + { + rs_frame[j][i] = h[ctr1]; + update_rs(parities[j], h[ctr1]); + // printf("header %d rs_frame[%d][%d] = %x \n", ctr1, j, i, h[ctr1]); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + } + else + { + rs_frame[j][i] = b[ctr3 % DATA_LEN]; + update_rs(parities[j], b[ctr3 % DATA_LEN]); + // printf("%d rs_frame[%d][%d] = %x %d \n", + // ctr1, j, i, b[ctr3 % DATA_LEN], ctr3 % DATA_LEN); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + ctr3++; + } + } + } + } + + printf("Parities "); + for (int m = 0; m < PARITY_LEN; m++) { + printf("%d ", parities[0][m]); + } + printf("\n"); + + int ctr2 = 0; + memset(data10,0,sizeof(data10)); + int rd = 0; + int nrd; + + for (i = 0; i < DATA_LEN * PAYLOADS + HEADER_LEN; i++) // 476 for BPSK + { + data10[ctr2] = (Encode_8b10b[rd][((int)data8[ctr2])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)data8[ctr2])] >> 10) & 1; + // printf ("data10[%d] = encoded data8[%d] = %x \n", + // ctr2, ctr2, data10[ctr2]); + + rd = nrd; // ^ nrd; + ctr2++; + } + + for (i = 0; i < PARITY_LEN; i++) + { + for (int j = 0; j < RS_FRAMES; j++) + { + data10[ctr2++] = (Encode_8b10b[rd][((int)parities[j][i])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)parities[j][i])] >> 10) & 1; + // printf ("data10[%d] = encoded parities[%d][%d] = %x \n", + // ctr2 - 1, j, i, data10[ctr2 - 1]); + + rd = nrd; + } + } + + int data; + int val; + int offset = 0; + + for (i = 1; i <= SYNC_BITS; i++) + { + copy_samples(); + if ( (i % SAMPLES) == 0) { + int bit = SYNC_BITS - i + 1; + val = sync; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d sync bit %d = %d \n", + // ctr, i, frames, bit, (data > 0) ); + if (DUV) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; +// if ( (ctr - smaller) > 0) +// { +// for (int j = 1; j <= smaller; j++) +// buffer[ctr - j] = buffer[ctr - j] * 0.4; +// } +// flip_ctr = ctr; + } + } + } + } + + for (i = 1; + i <= (10 * (HEADER_LEN + DATA_LEN * PAYLOADS + RS_FRAMES * PARITY_LEN) * 1); i++) // 572 + { + copy_samples(); +// if ( (i % SAMPLES) == 0) { + int symbol = (int)((i - 1)/ 10); + int bit = 10 - (i - symbol * 10); + val = data10[symbol]; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d data10[%d] = %x bit %d = %d \n", + // ctr/SAMPLES, i, frames, symbol, val, bit, (data > 0) ); + if (DUV) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; +// if ( (ctr - smaller) > 0) +// { +// for (int j = 1; j <= smaller; j ++) +// buffer[ctr - j] = buffer[ctr - j] * 0.4; +// } +// flip_ctr = ctr; + } + } +// } + } + } + write_wav("transmit.wav", BUF_LEN, buffer, S_RATE); + + int count; + for (count = 0; count < DATA_LEN; count++) { + printf("%02X", b[count]); + } + printf("\n"); + +return 0; +} + +// wav file generation code + +/* make_wav.c + * Creates a WAV file from an array of ints. + * Output is monophonic, signed 16-bit samples + * copyright + * Fri Jun 18 16:36:23 PDT 2010 Kevin Karplus + * Creative Commons license Attribution-NonCommercial + * http://creativecommons.org/licenses/by-nc/3.0/ + * + * Edited by Dolin Sergey. dlinyj@gmail.com + * April 11 12:58 2014 + */ + + // gcc -o make_enc_wav make_enc_wav.c -lm + // ./make_enc_wav + + /* + * TelemEncoding.h + * + * Created on: Feb 3, 2014 + * Author: fox + */ + +#include +#include +#include +#include +#include +#include + +//#include "make_wav.h" + +#define false 0 +#define true 1 + +//static int twosToInt(int val,int len); +//static int encodeB(short int *b, int index, int val); +//static int encodeA(short int *b, int index, int val); + + static int NOT_FRAME = /* 0fa */ 0xfa & 0x3ff; + static int FRAME = /* 0fa */ ~0xfa & 0x3ff; + +/* + * TelemEncoding.c + * + Fox-1 telemetry encoder + January 2014 Phil Karn KA9Q + + This file has two external functions: + void update_rs(unsigned char parity[32],unsigned char data); + int encode_8b10b(int *state,int data). + + update_rs() is the Reed-Solomon encoder. Its first argument is the 32-byte + encoder shift register, the second is the 8-bit data byte being encoded. It updates + the shift register in place and returns void. At the end of each frame, it contains + the parities ready for transmission, starting with parity[0]. + Be sure to zero this array before each new frame! + + encode_8b10b() is the 8b10b encoder. Its first argument is a pointer to a single integer + with the 1-bit encoder state (the current run disparity, or RD). Initialize it to 0 + JUST ONCE at startup (not between frames). + The second argument is the data byte being encoded. It updates the state and returns + an integer containing the 10-bit encoded word, right justified. + Transmit this word from left to right. + + The data argument is an int so it can hold the special value -1 to indicate end of frame; + it generates the 8b10b control word K.28.5, which is used as an inter-frame flag. + + Some assert() calls are made to verify legality of arguments. These can be turned off in + production code. + + + sample frame transmission code: + + unsigned char data[64]; // Data block to be sent + unsigned char parity[32]; // RS parities + void transmit_word(int); // User provided transmit function: 10 bits of data in bits 9....0 + int state,i; + + state = 0; // Only once at startup, not between frames + memset(parity,0,sizeof(parity); // Do this before every frame + // Transmit the data, updating the RS encoder + for(i=0;i<64;i++){ + update_rs(parity,data[i]); + transmit_word(encode_8b10b(&state,data[i]); + } + // Transmit the RS parities + for(i=0;i<32;i++) + transmit_word(encode_8b10b(&state,parity[i]); + + transmit_word(encode_8b10b(&state,-1); // Transmit end-of-frame flag +*/ + + +#include +//#include "Fox.h" +//#include "TelemEncoding.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define NN (0xff) // Frame size in symbols +#define A0 (NN) // special value for log(0) + + +// GF Antilog lookup table table +static unsigned char CCSDS_alpha_to[NN+1] = { +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, +0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, +0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, +0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, +0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, +0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, +0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, +0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, +0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, +0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, +0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, +0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, +0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, +0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, +0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, +0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, +}; + +// GF log lookup table. Special value represents log(0) +static unsigned char CCSDS_index_of[NN+1] = { + A0, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, + 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, + 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, +103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, + 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, +202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, +104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, +110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, + 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, +209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, +203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, +192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, +105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, +130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, +111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, + 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, +}; + +// Only half the coefficients are given here because the +// generator polynomial is palindromic; G0 = G32, G1 = G31, etc. +// Only G16 is unique +static unsigned char CCSDS_poly[] = { + 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, + 24, +}; + + +static inline int modnn(int x){ + while (x >= NN) { + x -= NN; + x = (x >> 8) + (x & NN); + } + return x; +} + + +// Update Reed-Solomon encoder +// parity -> 32-byte reed-solomon encoder state; clear this to zero before each frame +void update_rs( + unsigned char parity[32], // 32-byte encoder state; zero before each frame + unsigned char c) // Current data byte to update +{ + unsigned char feedback; + int j,t; + + assert(parity != NULL); + feedback = CCSDS_index_of[c ^ parity[0]]; + if(feedback != A0){ // only if feedback is non-zero + // Take advantage of palindromic polynomial to halve the multiplies + // Do G1...G15, which is the same as G17...G31 + for(j=1;j0) + { buf = word & 0xff; + fwrite(&buf, 1,1, wav_file); + num_bytes--; + word >>= 8; + } +} + +/* information about the WAV file format from + +http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ + + */ + +void write_wav(char * filename, unsigned long num_samples, short int * data, int s_rate) +{ + FILE* wav_file; + unsigned int sample_rate; + unsigned int num_channels; + unsigned int bytes_per_sample; + unsigned int byte_rate; + unsigned long i; /* counter for samples */ + + num_channels = 1; /* monoaural */ + bytes_per_sample = 2; + + if (s_rate<=0) sample_rate = 44100; + else sample_rate = (unsigned int) s_rate; + + byte_rate = sample_rate*num_channels*bytes_per_sample; + + wav_file = fopen(filename, "w"); + assert(wav_file); /* make sure it opened */ + + /* write RIFF header */ + fwrite("RIFF", 1, 4, wav_file); + write_little_endian(36 + bytes_per_sample* num_samples*num_channels, 4, wav_file); + fwrite("WAVE", 1, 4, wav_file); + + /* write fmt subchunk */ + fwrite("fmt ", 1, 4, wav_file); + write_little_endian(16, 4, wav_file); /* SubChunk1Size is 16 */ + write_little_endian(1, 2, wav_file); /* PCM is format 1 */ + write_little_endian(num_channels, 2, wav_file); + write_little_endian(sample_rate, 4, wav_file); + write_little_endian(byte_rate, 4, wav_file); + write_little_endian(num_channels*bytes_per_sample, 2, wav_file); /* block align */ + write_little_endian(8*bytes_per_sample, 2, wav_file); /* bits/sample */ + + /* write data subchunk */ + fwrite("data", 1, 4, wav_file); + write_little_endian(bytes_per_sample* num_samples*num_channels, 4, wav_file); + + for (i=0; i< num_samples; i++) + { write_little_endian((unsigned int)(data[i]),bytes_per_sample, wav_file); + } + + fclose(wav_file); +} + + + +//int main(int argc, char * argv[]) +//{ + +// return 0; +//} + +void write_wave(int i, short int *buf) +{ + if (DUV) + { +// if ((ctr - flip_ctr) < smaller) +// buffer[ctr++] = 0.1 * phase * (ctr - flip_ctr) / smaller; +// else + buf[i] = 0.25 * amplitude * phase; + } + else + { +// if ((ctr - flip_ctr) < smaller) + // buffer[ctr++] = (int)(amplitude * 0.4 * phase * + // sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + // else + buf[i] = (int)(amplitude * phase * sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + } + printf("%d %d \n", i, buf[i]); +} + +void copy_samples() +{ + if (phase == 0) + memcpy(&buffer[ptr], &phase0, size_of_phase); + else + memcpy(&buffer[ptr], &phase1, size_of_phase); + + ptr += size_of_phase; +} + +/** + * + * FOX 1 Telemetry Decoder + * @author chris.e.thompson g0kla/ac2cz + * + * Copyright (C) 2015 amsat.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General 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 License for more details. + * + * You should have received a copy of the GNU General License + * along with this program. If not, see . + * + * + * Static variables and methods to encode and decode 8b10b + * + * + */ + +int encodeA(short int *b, int index, int val) { +// printf("Encoding A\n"); + b[index] = val & 0xff; + b[index + 1] = (b[index + 1] & 0xf0) | ((val >> 8) & 0x0f); + return 0; +} + +int encodeB(short int *b, int index, int val) { +// printf("Encoding B\n"); + b[index] = (b[index] & 0x0f) | ((val << 4) & 0xf0); + b[index + 1] = (val >> 4 ) & 0xff; + return 0; +} + +int twosToInt(int val,int len) { // Convert twos compliment to integer +// from https://www.raspberrypi.org/forums/viewtopic.php?t=55815 + + if(val & (1 << (len - 1))) + val = val - (1 << len); + + return(val); +} diff --git a/afsk/main_not_working.c b/afsk/main_not_working.c new file mode 100644 index 00000000..05629dd8 --- /dev/null +++ b/afsk/main_not_working.c @@ -0,0 +1,1157 @@ +/* + * Transmits CubeSat Telemetry at 434.9MHz in AO-7 format + * + * Copyright Alan B. Johnston + * + * Portions Copyright (C) 2018 Jonathan Brandenburg + * + * 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 . + * + * INA219 Raspberry Pi wiringPi code is based on Adafruit Arduino wire code + * from https://github.com/adafruit/Adafruit_INA219. + */ + +#include +#include +#include +#include +#include +#include "status.h" +#include "ax5043.h" +#include "ax25.h" +#include "spi/ax5043spi.h" +#include +#include +#include +#include +#include "Adafruit_INA219.h" // From Adafruit INA219 library for Arduino +#include "make_wav.h" +#include +#include +#include +#include +#include +#define PORT 8080 + +#define A 1 +#define B 2 +#define C 3 +#define D 4 + +#define PLUS_X 0 +#define PLUS_Y 1 +#define PLUS_Z 2 +#define BAT 3 +#define MINUS_X 4 +#define MINUS_Y 5 +#define MINUS_Z 6 +#define BUS 7 +#define OFF -1 + +uint32_t tx_freq_hz = 434900000 + FREQUENCY_OFFSET; +uint32_t tx_channel = 0; + +ax5043_conf_t hax5043; +ax25_conf_t hax25; + +static void init_rf(); +int twosToInt(int val, int len); +int get_tlm(char *str); +int get_tlm_fox(); +int encodeA(short int *b, int index, int val); +int encodeB(short int *b, int index, int val); +void config_x25(); +void trans_x25(); +int upper_digit(int number); +int lower_digit(int number); + +#define S_RATE (48000) // (44100) +#define BUF_SIZE (S_RATE*10) /* 2 second buffer */ +/* +// BPSK Settings +#define BIT_RATE 1200 // 200 for DUV +#define FSK 0 // 1 for DUV +#define RS_FRAMES 3 // 3 frames for BPSK, 1 for DUV +#define PAYLOADS 6 // 1 for DUV +#define DATA_LEN 78 // 56 for DUV +#define RS_FRAME_LEN 159 // 64 for DUV +#define SYNC_BITS 31 // 10 for DUV +#define SYNC_WORD 0b1000111110011010010000101011101 // 0b0011111010 for DUV +#define HEADER_LEN 8 // 6 for DUV +*/ +// FSK Settings +#define BIT_RATE 200 +#define FSK 1 +#define RS_FRAMES 1 +#define PAYLOADS 1 +#define RS_FRAME_LEN 64 +#define HEADER_LEN 6 +#define DATA_LEN 58 +#define SYNC_BITS 10 +#define SYNC_WORD 0b0011111010 + + +#define PARITY_LEN 32 + +float amplitude = 32767/3; // 20000; // 32767/(10%amp+5%amp+100%amp) +float freq_Hz = 3000; // 1200 + +int smaller; +int flip_ctr = 0; +int phase = 1; +int ctr = 0; +int sock = 0; + +void write_to_buffer(int i, int symbol, int val); +void write_wave(); +#define SAMPLES (S_RATE / BIT_RATE) +<<<<<<< HEAD +#define FRAME_CNT 60// 11 //33 // Add 3 frames to the count +======= +#define FRAME_CNT 11// //33 // Add 3 frames to the count +>>>>>>> 363442c3e93a3058a0bb88473dc4fa192b6425ad + +//#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (8 + 6 * DATA_LEN + 96)) * SAMPLES) +#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN))) * SAMPLES) +short int buffer[BUF_LEN]; +short int data10[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +short int data8[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +int reset_count; +float uptime_sec; +long int uptime; +char call[5]; + +struct SensorConfig { + int fd; + uint16_t config; + int calValue; + int powerMultiplier; + int currentDivider; +}; + +struct SensorData { + double current; + double voltage; + double power; +}; + +/** + * @brief Read the data from one of the i2c current sensors. + * + * Reads the current data from the requested i2c current sensor configuration and + * stores it into a SensorData struct. An invalid file descriptor (i.e. less than zero) + * results in a SensorData struct being returned that has both its #current and #power members + * set to NAN. + * + * @param sensor A structure containing sensor configuration including the file descriptor. + * @return struct SensorData A struct that contains the current, voltage, and power readings + * from the requested sensor. + */ +struct SensorData read_sensor_data(struct SensorConfig sensor) { + struct SensorData data = { + .current = NAN, + .voltage = NAN, + .power = NAN }; + + if (sensor.fd < 0) { + return data; + } + // doesn't read negative currents accurately, shows -0.1mA + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CONFIG, sensor.config); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + int value = wiringPiI2CReadReg16(sensor.fd, INA219_REG_CURRENT); + data.current = (float) twosToInt(value, 16) / (float) sensor.currentDivider; + + wiringPiI2CWrite(sensor.fd, INA219_REG_BUSVOLTAGE); + delay(1); // Max 12-bit conversion time is 586us per sample + value = (wiringPiI2CRead(sensor.fd) << 8 ) | wiringPiI2CRead (sensor.fd); + data.voltage = ((float)(value >> 3) * 4) / 1000; + // power has very low resolution, seems to step in 512mW values + data.power = (float) wiringPiI2CReadReg16(sensor.fd, INA219_REG_POWER) * (float) sensor.powerMultiplier; + + return data; +} + +/** + * @brief Configures an i2c current sensor. + * + * Calculates the configuration values of the i2c sensor so that + * current, voltage, and power can be read using read_sensor_data. + * Supports 16V 400mA and 16V 2.0A settings. + * + * @param sensor A file descriptor that can be used to read from the sensor. + * @param milliAmps The mA configuration, either 400mA or 2A are supported. + * @return struct SensorConfig A struct that contains the configuraton of the sensor. + */ +//struct SensorConfig config_sensor(int sensor, int milliAmps) { +struct SensorConfig config_sensor(char *bus, int address, int milliAmps) { + struct SensorConfig data; + + if (access(bus, W_OK | R_OK) < 0) { // Test if I2C Bus is missing + printf("ERROR: %s bus not present \n", bus); + data.fd = OFF; + return (data); + } + + data.fd = wiringPiI2CSetupInterface(bus, address); + + data.config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_1_40MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_1S_532US | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + if (milliAmps == 400) { // INA219 16V 400mA configuration + data.calValue = 8192; + data.powerMultiplier = 1; + data.currentDivider = 20; // 40; in Adafruit config + } + else { // INA219 16V 2A configuration + data.calValue = 40960; + data.powerMultiplier = 2; + data.currentDivider = 10; // 20; in Adafruit config + } + + #ifdef DEBUG_LOGGING + printf("Sensor %s %x configuration: %d %d %d %d %d\n", bus, address, data.fd, + data.config, data.calValue, data.currentDivider, data.powerMultiplier); + #endif + return data; +} + +struct SensorConfig sensor[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorData reading[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorConfig tempSensor; + +char src_addr[5] = ""; +char dest_addr[5] = "CQ"; + +int main(int argc, char *argv[]) { + + if (argc > 1) { + strcpy(src_addr, argv[1]); + } + + wiringPiSetup (); + pinMode (0, OUTPUT); + + //setSpiChannel(SPI_CHANNEL); + //setSpiSpeed(SPI_SPEED); + //initializeSpi(); + + FILE* config_file = fopen("sim.cfg","r"); + if (config_file == NULL) + { + printf("Creating config file."); + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", "KU2Y", 100); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + } + + char* cfg_buf[100]; + fscanf(config_file, "%s %d", call, &reset_count); + fclose(config_file); + printf("%s %d\n", call, reset_count); + + reset_count = (reset_count + 1) % 0xffff; + + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", call, reset_count); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + + tempSensor = config_sensor("/dev/i2c-3", 0x48, 0); + + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); + + int ret; + uint8_t data[1024]; + + tx_freq_hz -= tx_channel * 50000; + + //init_rf(); + + ax25_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) src_addr, '1', + AX25_PREAMBLE_LEN, + AX25_POSTAMBLE_LEN); + +// socket open + int error = 0; + struct sockaddr_in address; + int valread; + struct sockaddr_in serv_addr; +// char *hello = "Hello from client"; +// char buffer[1024] = {0}; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + printf("\n Socket creation error \n"); + error = 1; + } + + memset(&serv_addr, '0', sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + // Convert IPv4 and IPv6 addresses from text to binary form + if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) + { + printf("\nInvalid address/ Address not supported \n"); + error = 1; + } + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + printf("\nConnection Failed \n"); + error = 1; + } + + /* Infinite loop */ + //for (;;) + + { + // sleep(1); // Delay 1 second + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting TLM Data\n"); + #endif + + char str[1000]; + // uint8_t b[64]; + char header_str[] = "\x03\xf0"; + strcpy(str, header_str); + + printf("%s-1>%s-1:", (uint8_t *)src_addr, (uint8_t *)dest_addr); + +// get_tlm(str); + get_tlm_fox(); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting ready to send\n"); + #endif +/* + char cmdbuffer[1000]; + FILE* transmit; + if (FSK == 1) { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/CubeSatSim/rpitx/rpitx -i- -m RF -f 434.9e3 2>&1", "r"); + } else { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr fir_interpolate_cc 2 | csdr dsb_fc | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff | sudo /home/pi/CubeSatSim/rpitx/sendiq -i /dev/stdin -s 96000 -f 434.9e6 -t float 2>&1", "r"); + } + fgets(cmdbuffer, 1000, transmit); + pclose(transmit); + printf("Results of transmit command: %s\n", cmdbuffer); +*/ + + +// printf("%s \n", b); +/* + digitalWrite (0, LOW); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Transmitting X.25 packet\n"); + #endif + memcpy(data, str, strnlen(str, 256)); + ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } + + ax5043_wait_for_transmit(); + + digitalWrite (0, HIGH); + + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } +*/ + } + + return 0; +} + +static void init_rf() { + int ret; + #ifdef DEBUG_LOGGING + fprintf(stderr,"Initializing AX5043\n"); + #endif + ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); + if (ret != PQWS_SUCCESS) { + fprintf(stderr, + "ERROR: Failed to initialize AX5043 with error code %d\n", ret); + exit(EXIT_FAILURE); + } +} + +// Returns lower digit of a number which must be less than 99 +// +int lower_digit(int number) { + + int digit = 0; + if (number < 100) + digit = number - ((int)(number/10) * 10); + else + fprintf(stderr,"ERROR: Not a digit in lower_digit!\n"); + return digit; +} + +// Returns upper digit of a number which must be less than 99 +// +int upper_digit(int number) { + + int digit = 0; + if (number < 100) + digit = (int)(number/10); + else + fprintf(stderr,"ERROR: Not a digit in upper_digit!\n"); + return digit; +} + +int get_tlm(char *str) { + + int tlm[7][5]; + memset(tlm, 0, sizeof tlm); + +// Reading I2C voltage and current sensors + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } + + tlm[1][A] = (int)(reading[BUS].voltage /15.0 + 0.5) % 100; // Current of 5V supply to Pi + tlm[1][B] = (int) (99.5 - reading[PLUS_X].current/10.0) % 100; // +X current [4] + tlm[1][C] = (int) (99.5 - reading[MINUS_X].current/10.0) % 100; // X- current [10] + tlm[1][D] = (int) (99.5 - reading[PLUS_Y].current/10.0) % 100; // +Y current [7] + + tlm[2][A] = (int) (99.5 - reading[MINUS_Y].current/10.0) % 100; // -Y current [10] + tlm[2][B] = (int) (99.5 - reading[PLUS_Z].current/10.0) % 100; // +Z current [10] // was 70/2m transponder power, AO-7 didn't have a Z panel + tlm[2][C] = (int) (99.5 - reading[MINUS_Z].current/10.0) % 100; // -Z current (was timestamp) + tlm[2][D] = (int)(50.5 + reading[BAT].current/10.0) % 100; // NiMH Battery current + + tlm[3][A] = abs((int)((reading[BAT].voltage * 10.0) - 65.5) % 100); + tlm[3][B] = (int)(reading[BUS].voltage * 10.0) % 100; // 5V supply to Pi + + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + tlm[4][A] = (int)((95.8 - temp)/1.48 + 0.5) % 100; + } + + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + tlm[4][B] = (int)((95.8 - cpuTemp)/1.48 + 0.5) % 100; + fclose (cpuTempSensor); + } + + tlm[6][B] = 0 ; + tlm[6][D] = 49 + rand() % 3; + + #ifdef DEBUG_LOGGING +// Display tlm + int k, j; + for (k = 1; k < 7; k++) { + for (j = 1; j < 5; j++) { + printf(" %2d ", tlm[k][j]); + } + printf("\n"); + } + #endif + + char tlm_str[1000]; + + char header_str[] = "hi hi "; + strcpy(str, header_str); +// printf("%s-1>%s-1:hi hi ", (uint8_t *)src_addr, (uint8_t *)dest_addr); + + int channel; + for (channel = 1; channel < 7; channel++) { + sprintf(tlm_str, "%d%d%d %d%d%d %d%d%d %d%d%d ", + channel, upper_digit(tlm[channel][1]), lower_digit(tlm[channel][1]), + channel, upper_digit(tlm[channel][2]), lower_digit(tlm[channel][2]), + channel, upper_digit(tlm[channel][3]), lower_digit(tlm[channel][3]), + channel, upper_digit(tlm[channel][4]), lower_digit(tlm[channel][4])); +// printf("%s",tlm_str); + strcat(str, tlm_str); + } +// printf("\n"); + +return; +} + +int get_tlm_fox() { + +// memset(b, 0, 64); + +// Reading I2C voltage and current sensors + + FILE* uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + fclose(uptime_file); + + int i; + long int sync = SYNC_WORD; + + smaller = S_RATE/(2 * freq_Hz); +/* + short int b[DATA_LEN] = {0x00,0x7E,0x03, + 0x00,0x00,0x00,0x00,0xE6,0x01,0x00,0x27,0xD1,0x02, + 0xE5,0x40,0x04,0x18,0xE1,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + short int h[HEADER_LEN] = {0x05,0x00,0x00,0x00,0x00,0x10,0x00,0x00}; +*/ + + short int b[DATA_LEN]; + memset(b, 0, sizeof(b)); + + short int h[HEADER_LEN]; + memset(h, 0, sizeof(h)); + + short int b10[DATA_LEN], h10[HEADER_LEN]; + short int rs_frame[RS_FRAMES][223]; + unsigned char parities[RS_FRAMES][PARITY_LEN],inputByte; +/* + int id = 7, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 8.95 * 100, battCurr = 48.6 * 10; + int posXv = 296, negXv = 45, posYv = 220, negYv = 68, + posZv = 280, negZv = 78; +*/ + int id = 7, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 0, battCurr = 0; + int posXv = 0, negXv = 0, posYv = 0, negYv = 0, + posZv = 0, negZv = 0; + int head_offset = 0; + + for (int frames = 0; frames < FRAME_CNT; frames++) + { + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } +/* + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + TxTemp = (int)((temp * 10.0) + 0.5); + encodeB(b, 34 + head_offset, TxTemp); + } +*/ + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + IHUcpuTemp = (int)((cpuTemp * 10.0) + 0.5); + encodeA(b, 39 + head_offset, IHUcpuTemp); + } + sleep(1); + + memset(rs_frame,0,sizeof(rs_frame)); + memset(parities,0,sizeof(parities)); + + FILE *uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + fclose(uptime_file); + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + + h[0] = (h[0] & 0xf8) | (id & 0x07); // 3 bits + printf("h[0] %x\n", h[0]); + h[0] = (h[0] & 0x07)| ((reset_count & 0x1f) << 3); + printf("h[0] %x\n", h[0]); + h[1] = (reset_count >> 5) & 0xff; + printf("h[1] %x\n", h[1]); + h[2] = (h[2] & 0xf8) | ((reset_count >> 13) & 0x07); + printf("h[2] %x\n", h[2]); + h[2] = (h[2] & 0x0e) | ((uptime & 0x1f) << 3); + printf("h[2] %x\n", h[2]); + h[3] = (uptime >> 5) & 0xff; + h[4] = (uptime >> 13) & 0xff; + h[5] = (h[5] & 0xf0) | ((uptime >> 21) & 0x0f); + h[5] = (h[5] & 0x0f) | (frm_type << 4); + + posXv = reading[PLUS_X].current * 10; + posYv = reading[PLUS_Y].current * 10; + posZv = reading[PLUS_Z].current * 10; + negXv = reading[MINUS_X].current * 10; + negYv = reading[MINUS_Y].current * 10; + negZv = reading[MINUS_Z].current * 10; + + batt_c_v = reading[BAT].voltage * 100; + battCurr = reading[BAT].current * 10; + + encodeA(b, 0 + head_offset, batt_a_v); + encodeB(b, 1 + head_offset, batt_b_v); + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); + encodeA(b, 12 + head_offset,posXv); + encodeB(b, 13 + head_offset,posYv); + encodeA(b, 15 + head_offset,posZv); + encodeB(b, 16 + head_offset,negXv); + encodeA(b, 18 + head_offset,negYv); + encodeB(b, 19 + head_offset,negZv); + +/* batt_c_v += 10; + battCurr -= 10; + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); +*/ + int ctr1 = 0; + int ctr3 = 0; + for (i = 0; i < RS_FRAME_LEN; i++) + { + for (int j = 0; j < RS_FRAMES ; j++) + { + if (!((i == (RS_FRAME_LEN - 1)) && (j == 2))) // skip last one for BPSK + { + if (ctr1 < HEADER_LEN) + { + rs_frame[j][i] = h[ctr1]; + update_rs(parities[j], h[ctr1]); + // printf("header %d rs_frame[%d][%d] = %x \n", ctr1, j, i, h[ctr1]); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + } + else + { + rs_frame[j][i] = b[ctr3 % DATA_LEN]; + update_rs(parities[j], b[ctr3 % DATA_LEN]); + // printf("%d rs_frame[%d][%d] = %x %d \n", + // ctr1, j, i, b[ctr3 % DATA_LEN], ctr3 % DATA_LEN); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + ctr3++; + } + } + } + } + + printf("Parities "); + for (int m = 0; m < PARITY_LEN; m++) { + printf("%d ", parities[0][m]); + } + printf("\n"); + + int ctr2 = 0; + memset(data10,0,sizeof(data10)); + int rd = 0; + int nrd; + + for (i = 0; i < DATA_LEN * PAYLOADS + HEADER_LEN; i++) // 476 for BPSK + { + data10[ctr2] = (Encode_8b10b[rd][((int)data8[ctr2])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)data8[ctr2])] >> 10) & 1; + // printf ("data10[%d] = encoded data8[%d] = %x \n", + // ctr2, ctr2, data10[ctr2]); + + rd = nrd; // ^ nrd; + ctr2++; + } + + for (i = 0; i < PARITY_LEN; i++) + { + for (int j = 0; j < RS_FRAMES; j++) + { + data10[ctr2++] = (Encode_8b10b[rd][((int)parities[j][i])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)parities[j][i])] >> 10) & 1; + // printf ("data10[%d] = encoded parities[%d][%d] = %x \n", + // ctr2 - 1, j, i, data10[ctr2 - 1]); + + rd = nrd; + } + } + + int data; + int val; + int offset = 0; + ctr = 0; + flip_ctr = 0; + phase = 1; + + for (i = 1; i <= SYNC_BITS * SAMPLES; i++) + { + write_wave(ctr); + if ( (i % SAMPLES) == 0) { + int bit = SYNC_BITS - i/SAMPLES + 1; + val = sync; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d sync bit %d = %d \n", + // ctr/SAMPLES, i, frames, bit, (data > 0) ); + if (FSK) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + + for (i = 1; + i <= (10 * (HEADER_LEN + DATA_LEN * PAYLOADS + RS_FRAMES * PARITY_LEN) * SAMPLES); i++) // 572 + { + write_wave(ctr); + if ( (i % SAMPLES) == 0) { + int symbol = (int)((i - 1)/ (SAMPLES * 10)); + int bit = 10 - (i - symbol * SAMPLES * 10) / SAMPLES + 1; + val = data10[symbol]; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d data10[%d] = %x bit %d = %d \n", + // ctr/SAMPLES, i, frames, symbol, val, bit, (data > 0) ); + if (FSK) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j ++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + } +// write_wav("transmit.wav", BUF_LEN, buffer, S_RATE); + + int error = 0; + int count; + for (count = 0; count < DATA_LEN; count++) { + printf("%02X", b[count]); + } + printf("\n"); + +// socket write + + if (!error) + { + printf("Sending buffer over socket!\n"); + send(sock, buffer, sizeof(buffer), 0); + } + +sleep(20); + +return 0; +} + +// wav file generation code + +/* make_wav.c + * Creates a WAV file from an array of ints. + * Output is monophonic, signed 16-bit samples + * copyright + * Fri Jun 18 16:36:23 PDT 2010 Kevin Karplus + * Creative Commons license Attribution-NonCommercial + * http://creativecommons.org/licenses/by-nc/3.0/ + * + * Edited by Dolin Sergey. dlinyj@gmail.com + * April 11 12:58 2014 + */ + + // gcc -o make_enc_wav make_enc_wav.c -lm + // ./make_enc_wav + + /* + * TelemEncoding.h + * + * Created on: Feb 3, 2014 + * Author: fox + */ + +#include +#include +#include +#include +#include +#include + +//#include "make_wav.h" + +#define false 0 +#define true 1 + +//static int twosToInt(int val,int len); +//static int encodeB(short int *b, int index, int val); +//static int encodeA(short int *b, int index, int val); + + static int NOT_FRAME = /* 0fa */ 0xfa & 0x3ff; + static int FRAME = /* 0fa */ ~0xfa & 0x3ff; + +/* + * TelemEncoding.c + * + Fox-1 telemetry encoder + January 2014 Phil Karn KA9Q + + This file has two external functions: + void update_rs(unsigned char parity[32],unsigned char data); + int encode_8b10b(int *state,int data). + + update_rs() is the Reed-Solomon encoder. Its first argument is the 32-byte + encoder shift register, the second is the 8-bit data byte being encoded. It updates + the shift register in place and returns void. At the end of each frame, it contains + the parities ready for transmission, starting with parity[0]. + Be sure to zero this array before each new frame! + + encode_8b10b() is the 8b10b encoder. Its first argument is a pointer to a single integer + with the 1-bit encoder state (the current run disparity, or RD). Initialize it to 0 + JUST ONCE at startup (not between frames). + The second argument is the data byte being encoded. It updates the state and returns + an integer containing the 10-bit encoded word, right justified. + Transmit this word from left to right. + + The data argument is an int so it can hold the special value -1 to indicate end of frame; + it generates the 8b10b control word K.28.5, which is used as an inter-frame flag. + + Some assert() calls are made to verify legality of arguments. These can be turned off in + production code. + + + sample frame transmission code: + + unsigned char data[64]; // Data block to be sent + unsigned char parity[32]; // RS parities + void transmit_word(int); // User provided transmit function: 10 bits of data in bits 9....0 + int state,i; + + state = 0; // Only once at startup, not between frames + memset(parity,0,sizeof(parity); // Do this before every frame + // Transmit the data, updating the RS encoder + for(i=0;i<64;i++){ + update_rs(parity,data[i]); + transmit_word(encode_8b10b(&state,data[i]); + } + // Transmit the RS parities + for(i=0;i<32;i++) + transmit_word(encode_8b10b(&state,parity[i]); + + transmit_word(encode_8b10b(&state,-1); // Transmit end-of-frame flag +*/ + + +#include +//#include "Fox.h" +//#include "TelemEncoding.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define NN (0xff) // Frame size in symbols +#define A0 (NN) // special value for log(0) + + +// GF Antilog lookup table table +static unsigned char CCSDS_alpha_to[NN+1] = { +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, +0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, +0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, +0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, +0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, +0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, +0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, +0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, +0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, +0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, +0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, +0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, +0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, +0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, +0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, +0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, +}; + +// GF log lookup table. Special value represents log(0) +static unsigned char CCSDS_index_of[NN+1] = { + A0, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, + 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, + 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, +103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, + 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, +202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, +104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, +110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, + 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, +209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, +203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, +192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, +105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, +130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, +111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, + 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, +}; + +// Only half the coefficients are given here because the +// generator polynomial is palindromic; G0 = G32, G1 = G31, etc. +// Only G16 is unique +static unsigned char CCSDS_poly[] = { + 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, + 24, +}; + + +static inline int modnn(int x){ + while (x >= NN) { + x -= NN; + x = (x >> 8) + (x & NN); + } + return x; +} + + +// Update Reed-Solomon encoder +// parity -> 32-byte reed-solomon encoder state; clear this to zero before each frame +void update_rs( + unsigned char parity[32], // 32-byte encoder state; zero before each frame + unsigned char c) // Current data byte to update +{ + unsigned char feedback; + int j,t; + + assert(parity != NULL); + feedback = CCSDS_index_of[c ^ parity[0]]; + if(feedback != A0){ // only if feedback is non-zero + // Take advantage of palindromic polynomial to halve the multiplies + // Do G1...G15, which is the same as G17...G31 + for(j=1;j0) + { buf = word & 0xff; + fwrite(&buf, 1,1, wav_file); + num_bytes--; + word >>= 8; + } +} + +/* information about the WAV file format from + +http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ + + */ + +void write_wav(char * filename, unsigned long num_samples, short int * data, int s_rate) +{ + FILE* wav_file; + unsigned int sample_rate; + unsigned int num_channels; + unsigned int bytes_per_sample; + unsigned int byte_rate; + unsigned long i; /* counter for samples */ + + num_channels = 1; /* monoaural */ + bytes_per_sample = 2; + + if (s_rate<=0) sample_rate = 44100; + else sample_rate = (unsigned int) s_rate; + + byte_rate = sample_rate*num_channels*bytes_per_sample; + + wav_file = fopen(filename, "w"); + assert(wav_file); /* make sure it opened */ + + /* write RIFF header */ + fwrite("RIFF", 1, 4, wav_file); + write_little_endian(36 + bytes_per_sample* num_samples*num_channels, 4, wav_file); + fwrite("WAVE", 1, 4, wav_file); + + /* write fmt subchunk */ + fwrite("fmt ", 1, 4, wav_file); + write_little_endian(16, 4, wav_file); /* SubChunk1Size is 16 */ + write_little_endian(1, 2, wav_file); /* PCM is format 1 */ + write_little_endian(num_channels, 2, wav_file); + write_little_endian(sample_rate, 4, wav_file); + write_little_endian(byte_rate, 4, wav_file); + write_little_endian(num_channels*bytes_per_sample, 2, wav_file); /* block align */ + write_little_endian(8*bytes_per_sample, 2, wav_file); /* bits/sample */ + + /* write data subchunk */ + fwrite("data", 1, 4, wav_file); + write_little_endian(bytes_per_sample* num_samples*num_channels, 4, wav_file); + + for (i=0; i< num_samples; i++) + { write_little_endian((unsigned int)(data[i]),bytes_per_sample, wav_file); + } + + fclose(wav_file); +} + + + +//int main(int argc, char * argv[]) +//{ + +// return 0; +//} + +void write_wave(int i) +{ + if (FSK) + { +// if ((ctr - flip_ctr) < smaller) +// buffer[ctr++] = 0.1 * phase * (ctr - flip_ctr) / smaller; +// else + buffer[ctr++] = 0.25 * amplitude * phase; + } + else + { + if ((ctr - flip_ctr) < smaller) + buffer[ctr++] = (int)(amplitude * 0.4 * phase * + sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + else + buffer[ctr++] = (int)(amplitude * phase * + sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + } +// printf("%d %d \n", i, buffer[ctr - 1]); + +} + +/** + * + * FOX 1 Telemetry Decoder + * @author chris.e.thompson g0kla/ac2cz + * + * Copyright (C) 2015 amsat.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General 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 License for more details. + * + * You should have received a copy of the GNU General License + * along with this program. If not, see . + * + * + * Static variables and methods to encode and decode 8b10b + * + * + */ + +int encodeA(short int *b, int index, int val) { +// printf("Encoding A\n"); + b[index] = val & 0xff; + b[index + 1] = (b[index + 1] & 0xf0) | ((val >> 8) & 0x0f); + return 0; +} + +int encodeB(short int *b, int index, int val) { +// printf("Encoding B\n"); + b[index] = (b[index] & 0x0f) | ((val << 4) & 0xf0); + b[index + 1] = (val >> 4 ) & 0xff; + return 0; +} + +int twosToInt(int val,int len) { // Convert twos compliment to integer +// from https://www.raspberrypi.org/forums/viewtopic.php?t=55815 + + if(val & (1 << (len - 1))) + val = val - (1 << len); + + return(val); +} diff --git a/afsk/main_old.c b/afsk/main_old.c new file mode 100644 index 00000000..5d43b46f --- /dev/null +++ b/afsk/main_old.c @@ -0,0 +1,1144 @@ +/* + * Transmits CubeSat Telemetry at 434.9MHz in AO-7 format + * + * Copyright Alan B. Johnston + * + * Portions Copyright (C) 2018 Jonathan Brandenburg + * + * 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 . + * + * INA219 Raspberry Pi wiringPi code is based on Adafruit Arduino wire code + * from https://github.com/adafruit/Adafruit_INA219. + */ + +#include +#include +#include +#include +#include +#include "status.h" +#include "ax5043.h" +#include "ax25.h" +#include "spi/ax5043spi.h" +#include +#include +#include +#include +#include "Adafruit_INA219.h" // From Adafruit INA219 library for Arduino +#include "make_wav.h" +#include +#include +#include +#include +#include +#define PORT 8080 + +#define A 1 +#define B 2 +#define C 3 +#define D 4 + +#define PLUS_X 0 +#define PLUS_Y 1 +#define PLUS_Z 2 +#define BAT 3 +#define MINUS_X 4 +#define MINUS_Y 5 +#define MINUS_Z 6 +#define BUS 7 +#define OFF -1 + +uint32_t tx_freq_hz = 434900000 + FREQUENCY_OFFSET; +uint32_t tx_channel = 0; + +ax5043_conf_t hax5043; +ax25_conf_t hax25; + +static void init_rf(); +int twosToInt(int val, int len); +int get_tlm(char *str); +int get_tlm_fox(); +int encodeA(short int *b, int index, int val); +int encodeB(short int *b, int index, int val); +void config_x25(); +void trans_x25(); +int upper_digit(int number); +int lower_digit(int number); + +#define S_RATE (48000) // (44100) +#define BUF_SIZE (S_RATE*10) /* 2 second buffer */ +/* +// BPSK Settings +#define BIT_RATE 1200 // 200 for DUV +#define FSK 0 // 1 for DUV +#define RS_FRAMES 3 // 3 frames for BPSK, 1 for DUV +#define PAYLOADS 6 // 1 for DUV +#define DATA_LEN 78 // 56 for DUV +#define RS_FRAME_LEN 159 // 64 for DUV +#define SYNC_BITS 31 // 10 for DUV +#define SYNC_WORD 0b1000111110011010010000101011101 // 0b0011111010 for DUV +#define HEADER_LEN 8 // 6 for DUV +*/ +// FSK Settings +#define BIT_RATE 200 +#define FSK 1 +#define RS_FRAMES 1 +#define PAYLOADS 1 +#define RS_FRAME_LEN 64 +#define HEADER_LEN 6 +#define DATA_LEN 58 +#define SYNC_BITS 10 +#define SYNC_WORD 0b0011111010 + + +#define PARITY_LEN 32 + +float amplitude = 32767/3; // 20000; // 32767/(10%amp+5%amp+100%amp) +float freq_Hz = 3000; // 1200 + +int smaller; +int flip_ctr = 0; +int phase = 1; +int ctr = 0; +void write_to_buffer(int i, int symbol, int val); +void write_wave(); +#define SAMPLES (S_RATE / BIT_RATE) +#define FRAME_CNT 60// 11 //33 // Add 3 frames to the count + +//#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (8 + 6 * DATA_LEN + 96)) * SAMPLES) +#define BUF_LEN (FRAME_CNT * (SYNC_BITS + 10 * (HEADER_LEN + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN))) * SAMPLES) +short int buffer[BUF_LEN]; +short int data10[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +short int data8[8 + RS_FRAMES * (RS_FRAME_LEN + PARITY_LEN)]; +int reset_count; +float uptime_sec; +long int uptime; +char call[5]; + +struct SensorConfig { + int fd; + uint16_t config; + int calValue; + int powerMultiplier; + int currentDivider; +}; + +struct SensorData { + double current; + double voltage; + double power; +}; + +/** + * @brief Read the data from one of the i2c current sensors. + * + * Reads the current data from the requested i2c current sensor configuration and + * stores it into a SensorData struct. An invalid file descriptor (i.e. less than zero) + * results in a SensorData struct being returned that has both its #current and #power members + * set to NAN. + * + * @param sensor A structure containing sensor configuration including the file descriptor. + * @return struct SensorData A struct that contains the current, voltage, and power readings + * from the requested sensor. + */ +struct SensorData read_sensor_data(struct SensorConfig sensor) { + struct SensorData data = { + .current = NAN, + .voltage = NAN, + .power = NAN }; + + if (sensor.fd < 0) { + return data; + } + // doesn't read negative currents accurately, shows -0.1mA + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CONFIG, sensor.config); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + int value = wiringPiI2CReadReg16(sensor.fd, INA219_REG_CURRENT); + data.current = (float) twosToInt(value, 16) / (float) sensor.currentDivider; + + wiringPiI2CWrite(sensor.fd, INA219_REG_BUSVOLTAGE); + delay(1); // Max 12-bit conversion time is 586us per sample + value = (wiringPiI2CRead(sensor.fd) << 8 ) | wiringPiI2CRead (sensor.fd); + data.voltage = ((float)(value >> 3) * 4) / 1000; + // power has very low resolution, seems to step in 512mW values + data.power = (float) wiringPiI2CReadReg16(sensor.fd, INA219_REG_POWER) * (float) sensor.powerMultiplier; + + return data; +} + +/** + * @brief Configures an i2c current sensor. + * + * Calculates the configuration values of the i2c sensor so that + * current, voltage, and power can be read using read_sensor_data. + * Supports 16V 400mA and 16V 2.0A settings. + * + * @param sensor A file descriptor that can be used to read from the sensor. + * @param milliAmps The mA configuration, either 400mA or 2A are supported. + * @return struct SensorConfig A struct that contains the configuraton of the sensor. + */ +//struct SensorConfig config_sensor(int sensor, int milliAmps) { +struct SensorConfig config_sensor(char *bus, int address, int milliAmps) { + struct SensorConfig data; + + if (access(bus, W_OK | R_OK) < 0) { // Test if I2C Bus is missing + printf("ERROR: %s bus not present \n", bus); + data.fd = OFF; + return (data); + } + + data.fd = wiringPiI2CSetupInterface(bus, address); + + data.config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_1_40MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_1S_532US | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + if (milliAmps == 400) { // INA219 16V 400mA configuration + data.calValue = 8192; + data.powerMultiplier = 1; + data.currentDivider = 20; // 40; in Adafruit config + } + else { // INA219 16V 2A configuration + data.calValue = 40960; + data.powerMultiplier = 2; + data.currentDivider = 10; // 20; in Adafruit config + } + + #ifdef DEBUG_LOGGING + printf("Sensor %s %x configuration: %d %d %d %d %d\n", bus, address, data.fd, + data.config, data.calValue, data.currentDivider, data.powerMultiplier); + #endif + return data; +} + +struct SensorConfig sensor[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorData reading[8]; // 7 current sensors in Solar Power PCB plus one in MoPower UPS V2 +struct SensorConfig tempSensor; + +char src_addr[5] = ""; +char dest_addr[5] = "CQ"; + +int main(int argc, char *argv[]) { + + if (argc > 1) { + strcpy(src_addr, argv[1]); + } + + wiringPiSetup (); + pinMode (0, OUTPUT); + + //setSpiChannel(SPI_CHANNEL); + //setSpiSpeed(SPI_SPEED); + //initializeSpi(); + + FILE* config_file = fopen("sim.cfg","r"); + if (config_file == NULL) + { + printf("Creating config file."); + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", "KU2Y", 100); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + } + + char* cfg_buf[100]; + fscanf(config_file, "%s %d", call, &reset_count); + fclose(config_file); + printf("%s %d\n", call, reset_count); + + reset_count = (reset_count + 1) % 0xffff; + + config_file = fopen("sim.cfg","w"); + fprintf(config_file, "%s %d", call, reset_count); + fclose(config_file); + config_file = fopen("sim.cfg","r"); + + tempSensor = config_sensor("/dev/i2c-3", 0x48, 0); + + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); + + int ret; + uint8_t data[1024]; + + tx_freq_hz -= tx_channel * 50000; + + //init_rf(); + + ax25_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) src_addr, '1', + AX25_PREAMBLE_LEN, + AX25_POSTAMBLE_LEN); + + /* Infinite loop */ + //for (;;) + + { + // sleep(1); // Delay 1 second + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting TLM Data\n"); + #endif + + char str[1000]; + // uint8_t b[64]; + char header_str[] = "\x03\xf0"; + strcpy(str, header_str); + + printf("%s-1>%s-1:", (uint8_t *)src_addr, (uint8_t *)dest_addr); + +// get_tlm(str); + get_tlm_fox(); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Getting ready to send\n"); + #endif +/* + char cmdbuffer[1000]; + FILE* transmit; + if (FSK == 1) { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr gain_ff 7000 | csdr convert_f_samplerf 20833 | sudo /home/pi/CubeSatSim/rpitx/rpitx -i- -m RF -f 434.9e3 2>&1", "r"); + } else { + transmit = popen("sudo cat /home/pi/CubeSatSim/transmit.wav | csdr convert_i16_f | csdr fir_interpolate_cc 2 | csdr dsb_fc | csdr bandpass_fir_fft_cc 0.002 0.06 0.01 | csdr fastagc_ff | sudo /home/pi/CubeSatSim/rpitx/sendiq -i /dev/stdin -s 96000 -f 434.9e6 -t float 2>&1", "r"); + } + fgets(cmdbuffer, 1000, transmit); + pclose(transmit); + printf("Results of transmit command: %s\n", cmdbuffer); +*/ + + +// printf("%s \n", b); +/* + digitalWrite (0, LOW); + + #ifdef DEBUG_LOGGING + fprintf(stderr,"INFO: Transmitting X.25 packet\n"); + #endif + memcpy(data, str, strnlen(str, 256)); + ret = ax25_tx_frame(&hax25, &hax5043, data, strnlen(str, 256)); + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } + + ax5043_wait_for_transmit(); + + digitalWrite (0, HIGH); + + if (ret) { + fprintf(stderr, + "ERROR: Failed to transmit entire AX.25 frame with error code %d\n", + ret); + exit(EXIT_FAILURE); + } +*/ + } + + return 0; +} + +static void init_rf() { + int ret; + #ifdef DEBUG_LOGGING + fprintf(stderr,"Initializing AX5043\n"); + #endif + ret = ax5043_init(&hax5043, XTAL_FREQ_HZ, VCO_INTERNAL); + if (ret != PQWS_SUCCESS) { + fprintf(stderr, + "ERROR: Failed to initialize AX5043 with error code %d\n", ret); + exit(EXIT_FAILURE); + } +} + +// Returns lower digit of a number which must be less than 99 +// +int lower_digit(int number) { + + int digit = 0; + if (number < 100) + digit = number - ((int)(number/10) * 10); + else + fprintf(stderr,"ERROR: Not a digit in lower_digit!\n"); + return digit; +} + +// Returns upper digit of a number which must be less than 99 +// +int upper_digit(int number) { + + int digit = 0; + if (number < 100) + digit = (int)(number/10); + else + fprintf(stderr,"ERROR: Not a digit in upper_digit!\n"); + return digit; +} + +int get_tlm(char *str) { + + int tlm[7][5]; + memset(tlm, 0, sizeof tlm); + +// Reading I2C voltage and current sensors + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } + + tlm[1][A] = (int)(reading[BUS].voltage /15.0 + 0.5) % 100; // Current of 5V supply to Pi + tlm[1][B] = (int) (99.5 - reading[PLUS_X].current/10.0) % 100; // +X current [4] + tlm[1][C] = (int) (99.5 - reading[MINUS_X].current/10.0) % 100; // X- current [10] + tlm[1][D] = (int) (99.5 - reading[PLUS_Y].current/10.0) % 100; // +Y current [7] + + tlm[2][A] = (int) (99.5 - reading[MINUS_Y].current/10.0) % 100; // -Y current [10] + tlm[2][B] = (int) (99.5 - reading[PLUS_Z].current/10.0) % 100; // +Z current [10] // was 70/2m transponder power, AO-7 didn't have a Z panel + tlm[2][C] = (int) (99.5 - reading[MINUS_Z].current/10.0) % 100; // -Z current (was timestamp) + tlm[2][D] = (int)(50.5 + reading[BAT].current/10.0) % 100; // NiMH Battery current + + tlm[3][A] = abs((int)((reading[BAT].voltage * 10.0) - 65.5) % 100); + tlm[3][B] = (int)(reading[BUS].voltage * 10.0) % 100; // 5V supply to Pi + + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + tlm[4][A] = (int)((95.8 - temp)/1.48 + 0.5) % 100; + } + + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + tlm[4][B] = (int)((95.8 - cpuTemp)/1.48 + 0.5) % 100; + fclose (cpuTempSensor); + } + + tlm[6][B] = 0 ; + tlm[6][D] = 49 + rand() % 3; + + #ifdef DEBUG_LOGGING +// Display tlm + int k, j; + for (k = 1; k < 7; k++) { + for (j = 1; j < 5; j++) { + printf(" %2d ", tlm[k][j]); + } + printf("\n"); + } + #endif + + char tlm_str[1000]; + + char header_str[] = "hi hi "; + strcpy(str, header_str); +// printf("%s-1>%s-1:hi hi ", (uint8_t *)src_addr, (uint8_t *)dest_addr); + + int channel; + for (channel = 1; channel < 7; channel++) { + sprintf(tlm_str, "%d%d%d %d%d%d %d%d%d %d%d%d ", + channel, upper_digit(tlm[channel][1]), lower_digit(tlm[channel][1]), + channel, upper_digit(tlm[channel][2]), lower_digit(tlm[channel][2]), + channel, upper_digit(tlm[channel][3]), lower_digit(tlm[channel][3]), + channel, upper_digit(tlm[channel][4]), lower_digit(tlm[channel][4])); +// printf("%s",tlm_str); + strcat(str, tlm_str); + } +// printf("\n"); + +return; +} + +int get_tlm_fox() { + +// memset(b, 0, 64); + +// Reading I2C voltage and current sensors + + FILE* uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + fclose(uptime_file); + + int i; + long int sync = SYNC_WORD; + + smaller = S_RATE/(2 * freq_Hz); +/* + short int b[DATA_LEN] = {0x00,0x7E,0x03, + 0x00,0x00,0x00,0x00,0xE6,0x01,0x00,0x27,0xD1,0x02, + 0xE5,0x40,0x04,0x18,0xE1,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + short int h[HEADER_LEN] = {0x05,0x00,0x00,0x00,0x00,0x10,0x00,0x00}; +*/ + + short int b[DATA_LEN]; + memset(b, 0, sizeof(b)); + + short int h[HEADER_LEN]; + memset(h, 0, sizeof(h)); + + short int b10[DATA_LEN], h10[HEADER_LEN]; + short int rs_frame[RS_FRAMES][223]; + unsigned char parities[RS_FRAMES][PARITY_LEN],inputByte; +/* + int id = 7, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 8.95 * 100, battCurr = 48.6 * 10; + int posXv = 296, negXv = 45, posYv = 220, negYv = 68, + posZv = 280, negZv = 78; +*/ + int id = 7, frm_type = 0x01, TxTemp = 0, IHUcpuTemp = 0; + int batt_a_v = 0, batt_b_v = 0, batt_c_v = 0, battCurr = 0; + int posXv = 0, negXv = 0, posYv = 0, negYv = 0, + posZv = 0, negZv = 0; + int head_offset = 0; + + for (int frames = 0; frames < FRAME_CNT; frames++) + { + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); + #ifdef DEBUG_LOGGING + printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", + count, reading[count].voltage, reading[count].current, reading[count].power); + #endif + } +/* + if (tempSensor.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(tempSensor.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + + #ifdef DEBUG_LOGGING + printf("Temp Sensor Read: %6.1f\n", temp); + #endif + + TxTemp = (int)((temp * 10.0) + 0.5); + encodeB(b, 34 + head_offset, TxTemp); + } +*/ + FILE *cpuTempSensor = fopen("/sys/class/thermal/thermal_zone0/temp", "r"); + if (cpuTempSensor) { + double cpuTemp; + fscanf (cpuTempSensor, "%lf", &cpuTemp); + cpuTemp /= 1000; + + #ifdef DEBUG_LOGGING + printf("CPU Temp Read: %6.1f\n", cpuTemp); + #endif + + IHUcpuTemp = (int)((cpuTemp * 10.0) + 0.5); + encodeA(b, 39 + head_offset, IHUcpuTemp); + } + sleep(1); + + memset(rs_frame,0,sizeof(rs_frame)); + memset(parities,0,sizeof(parities)); + + FILE *uptime_file = fopen("/proc/uptime", "r"); + fscanf(uptime_file, "%f", &uptime_sec); + uptime = (int) uptime_sec; + fclose(uptime_file); + printf("Reset Count: %d Uptime since Reset: %ld \n", reset_count, uptime); + + h[0] = (h[0] & 0xf8) | (id & 0x07); // 3 bits + printf("h[0] %x\n", h[0]); + h[0] = (h[0] & 0x07)| ((reset_count & 0x1f) << 3); + printf("h[0] %x\n", h[0]); + h[1] = (reset_count >> 5) & 0xff; + printf("h[1] %x\n", h[1]); + h[2] = (h[2] & 0xf8) | ((reset_count >> 13) & 0x07); + printf("h[2] %x\n", h[2]); + h[2] = (h[2] & 0x0e) | ((uptime & 0x1f) << 3); + printf("h[2] %x\n", h[2]); + h[3] = (uptime >> 5) & 0xff; + h[4] = (uptime >> 13) & 0xff; + h[5] = (h[5] & 0xf0) | ((uptime >> 21) & 0x0f); + h[5] = (h[5] & 0x0f) | (frm_type << 4); + + posXv = reading[PLUS_X].current * 10; + posYv = reading[PLUS_Y].current * 10; + posZv = reading[PLUS_Z].current * 10; + negXv = reading[MINUS_X].current * 10; + negYv = reading[MINUS_Y].current * 10; + negZv = reading[MINUS_Z].current * 10; + + batt_c_v = reading[BAT].voltage * 100; + battCurr = reading[BAT].current * 10; + + encodeA(b, 0 + head_offset, batt_a_v); + encodeB(b, 1 + head_offset, batt_b_v); + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); + encodeA(b, 12 + head_offset,posXv); + encodeB(b, 13 + head_offset,posYv); + encodeA(b, 15 + head_offset,posZv); + encodeB(b, 16 + head_offset,negXv); + encodeA(b, 18 + head_offset,negYv); + encodeB(b, 19 + head_offset,negZv); + +/* batt_c_v += 10; + battCurr -= 10; + encodeA(b, 3 + head_offset, batt_c_v); + encodeA(b, 9 + head_offset, battCurr); +*/ + int ctr1 = 0; + int ctr3 = 0; + for (i = 0; i < RS_FRAME_LEN; i++) + { + for (int j = 0; j < RS_FRAMES ; j++) + { + if (!((i == (RS_FRAME_LEN - 1)) && (j == 2))) // skip last one for BPSK + { + if (ctr1 < HEADER_LEN) + { + rs_frame[j][i] = h[ctr1]; + update_rs(parities[j], h[ctr1]); + // printf("header %d rs_frame[%d][%d] = %x \n", ctr1, j, i, h[ctr1]); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + } + else + { + rs_frame[j][i] = b[ctr3 % DATA_LEN]; + update_rs(parities[j], b[ctr3 % DATA_LEN]); + // printf("%d rs_frame[%d][%d] = %x %d \n", + // ctr1, j, i, b[ctr3 % DATA_LEN], ctr3 % DATA_LEN); + data8[ctr1++] = rs_frame[j][i]; + // printf ("data8[%d] = %x \n", ctr1 - 1, rs_frame[j][i]); + ctr3++; + } + } + } + } + + printf("Parities "); + for (int m = 0; m < PARITY_LEN; m++) { + printf("%d ", parities[0][m]); + } + printf("\n"); + + int ctr2 = 0; + memset(data10,0,sizeof(data10)); + int rd = 0; + int nrd; + + for (i = 0; i < DATA_LEN * PAYLOADS + HEADER_LEN; i++) // 476 for BPSK + { + data10[ctr2] = (Encode_8b10b[rd][((int)data8[ctr2])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)data8[ctr2])] >> 10) & 1; + // printf ("data10[%d] = encoded data8[%d] = %x \n", + // ctr2, ctr2, data10[ctr2]); + + rd = nrd; // ^ nrd; + ctr2++; + } + + for (i = 0; i < PARITY_LEN; i++) + { + for (int j = 0; j < RS_FRAMES; j++) + { + data10[ctr2++] = (Encode_8b10b[rd][((int)parities[j][i])] & 0x3ff); + nrd = (Encode_8b10b[rd][((int)parities[j][i])] >> 10) & 1; + // printf ("data10[%d] = encoded parities[%d][%d] = %x \n", + // ctr2 - 1, j, i, data10[ctr2 - 1]); + + rd = nrd; + } + } + + int data; + int val; + int offset = 0; + + for (i = 1; i <= SYNC_BITS * SAMPLES; i++) + { + write_wave(ctr); + if ( (i % SAMPLES) == 0) { + int bit = SYNC_BITS - i/SAMPLES + 1; + val = sync; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d sync bit %d = %d \n", + // ctr/SAMPLES, i, frames, bit, (data > 0) ); + if (FSK) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + + for (i = 1; + i <= (10 * (HEADER_LEN + DATA_LEN * PAYLOADS + RS_FRAMES * PARITY_LEN) * SAMPLES); i++) // 572 + { + write_wave(ctr); + if ( (i % SAMPLES) == 0) { + int symbol = (int)((i - 1)/ (SAMPLES * 10)); + int bit = 10 - (i - symbol * SAMPLES * 10) / SAMPLES + 1; + val = data10[symbol]; + data = val & 1 << (bit - 1); + // printf ("%d i: %d new frame %d data10[%d] = %x bit %d = %d \n", + // ctr/SAMPLES, i, frames, symbol, val, bit, (data > 0) ); + if (FSK) + { + phase = ((data != 0) * 2) - 1; + // printf("Sending a %d\n", phase); + } + else + { + if (data == 0) { + phase *= -1; + if ( (ctr - smaller) > 0) + { + for (int j = 1; j <= smaller; j ++) + buffer[ctr - j] = buffer[ctr - j] * 0.4; + } + flip_ctr = ctr; + } + } + } + } + } +// write_wav("transmit.wav", BUF_LEN, buffer, S_RATE); + + int error = 0; + int count; + for (count = 0; count < DATA_LEN; count++) { + printf("%02X", b[count]); + } + printf("\n"); + +// socket write + + struct sockaddr_in address; + int sock = 0, valread; + struct sockaddr_in serv_addr; +// char *hello = "Hello from client"; +// char buffer[1024] = {0}; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + printf("\n Socket creation error \n"); + error = 1; + } + + memset(&serv_addr, '0', sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + // Convert IPv4 and IPv6 addresses from text to binary form + if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) + { + printf("\nInvalid address/ Address not supported \n"); + error = 1; + } + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + printf("\nConnection Failed \n"); + error = 1; + } + + if (!error) + { + printf("Sending buffer over socket!\n"); + send(sock, buffer, sizeof(buffer), 0); + } + +return 0; +} + +// wav file generation code + +/* make_wav.c + * Creates a WAV file from an array of ints. + * Output is monophonic, signed 16-bit samples + * copyright + * Fri Jun 18 16:36:23 PDT 2010 Kevin Karplus + * Creative Commons license Attribution-NonCommercial + * http://creativecommons.org/licenses/by-nc/3.0/ + * + * Edited by Dolin Sergey. dlinyj@gmail.com + * April 11 12:58 2014 + */ + + // gcc -o make_enc_wav make_enc_wav.c -lm + // ./make_enc_wav + + /* + * TelemEncoding.h + * + * Created on: Feb 3, 2014 + * Author: fox + */ + +#include +#include +#include +#include +#include +#include + +//#include "make_wav.h" + +#define false 0 +#define true 1 + +//static int twosToInt(int val,int len); +//static int encodeB(short int *b, int index, int val); +//static int encodeA(short int *b, int index, int val); + + static int NOT_FRAME = /* 0fa */ 0xfa & 0x3ff; + static int FRAME = /* 0fa */ ~0xfa & 0x3ff; + +/* + * TelemEncoding.c + * + Fox-1 telemetry encoder + January 2014 Phil Karn KA9Q + + This file has two external functions: + void update_rs(unsigned char parity[32],unsigned char data); + int encode_8b10b(int *state,int data). + + update_rs() is the Reed-Solomon encoder. Its first argument is the 32-byte + encoder shift register, the second is the 8-bit data byte being encoded. It updates + the shift register in place and returns void. At the end of each frame, it contains + the parities ready for transmission, starting with parity[0]. + Be sure to zero this array before each new frame! + + encode_8b10b() is the 8b10b encoder. Its first argument is a pointer to a single integer + with the 1-bit encoder state (the current run disparity, or RD). Initialize it to 0 + JUST ONCE at startup (not between frames). + The second argument is the data byte being encoded. It updates the state and returns + an integer containing the 10-bit encoded word, right justified. + Transmit this word from left to right. + + The data argument is an int so it can hold the special value -1 to indicate end of frame; + it generates the 8b10b control word K.28.5, which is used as an inter-frame flag. + + Some assert() calls are made to verify legality of arguments. These can be turned off in + production code. + + + sample frame transmission code: + + unsigned char data[64]; // Data block to be sent + unsigned char parity[32]; // RS parities + void transmit_word(int); // User provided transmit function: 10 bits of data in bits 9....0 + int state,i; + + state = 0; // Only once at startup, not between frames + memset(parity,0,sizeof(parity); // Do this before every frame + // Transmit the data, updating the RS encoder + for(i=0;i<64;i++){ + update_rs(parity,data[i]); + transmit_word(encode_8b10b(&state,data[i]); + } + // Transmit the RS parities + for(i=0;i<32;i++) + transmit_word(encode_8b10b(&state,parity[i]); + + transmit_word(encode_8b10b(&state,-1); // Transmit end-of-frame flag +*/ + + +#include +//#include "Fox.h" +//#include "TelemEncoding.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define NN (0xff) // Frame size in symbols +#define A0 (NN) // special value for log(0) + + +// GF Antilog lookup table table +static unsigned char CCSDS_alpha_to[NN+1] = { +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xad,0xdd,0x3d,0x7a,0xf4, +0x6f,0xde,0x3b,0x76,0xec,0x5f,0xbe,0xfb,0x71,0xe2,0x43,0x86,0x8b,0x91,0xa5,0xcd, +0x1d,0x3a,0x74,0xe8,0x57,0xae,0xdb,0x31,0x62,0xc4,0x0f,0x1e,0x3c,0x78,0xf0,0x67, +0xce,0x1b,0x36,0x6c,0xd8,0x37,0x6e,0xdc,0x3f,0x7e,0xfc,0x7f,0xfe,0x7b,0xf6,0x6b, +0xd6,0x2b,0x56,0xac,0xdf,0x39,0x72,0xe4,0x4f,0x9e,0xbb,0xf1,0x65,0xca,0x13,0x26, +0x4c,0x98,0xb7,0xe9,0x55,0xaa,0xd3,0x21,0x42,0x84,0x8f,0x99,0xb5,0xed,0x5d,0xba, +0xf3,0x61,0xc2,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0x07,0x0e,0x1c,0x38,0x70,0xe0, +0x47,0x8e,0x9b,0xb1,0xe5,0x4d,0x9a,0xb3,0xe1,0x45,0x8a,0x93,0xa1,0xc5,0x0d,0x1a, +0x34,0x68,0xd0,0x27,0x4e,0x9c,0xbf,0xf9,0x75,0xea,0x53,0xa6,0xcb,0x11,0x22,0x44, +0x88,0x97,0xa9,0xd5,0x2d,0x5a,0xb4,0xef,0x59,0xb2,0xe3,0x41,0x82,0x83,0x81,0x85, +0x8d,0x9d,0xbd,0xfd,0x7d,0xfa,0x73,0xe6,0x4b,0x96,0xab,0xd1,0x25,0x4a,0x94,0xaf, +0xd9,0x35,0x6a,0xd4,0x2f,0x5e,0xbc,0xff,0x79,0xf2,0x63,0xc6,0x0b,0x16,0x2c,0x58, +0xb0,0xe7,0x49,0x92,0xa3,0xc1,0x05,0x0a,0x14,0x28,0x50,0xa0,0xc7,0x09,0x12,0x24, +0x48,0x90,0xa7,0xc9,0x15,0x2a,0x54,0xa8,0xd7,0x29,0x52,0xa4,0xcf,0x19,0x32,0x64, +0xc8,0x17,0x2e,0x5c,0xb8,0xf7,0x69,0xd2,0x23,0x46,0x8c,0x9f,0xb9,0xf5,0x6d,0xda, +0x33,0x66,0xcc,0x1f,0x3e,0x7c,0xf8,0x77,0xee,0x5b,0xb6,0xeb,0x51,0xa2,0xc3,0x00, +}; + +// GF log lookup table. Special value represents log(0) +static unsigned char CCSDS_index_of[NN+1] = { + A0, 0, 1, 99, 2,198,100,106, 3,205,199,188,101,126,107, 42, + 4,141,206, 78,200,212,189,225,102,221,127, 49,108, 32, 43,243, + 5, 87,142,232,207,172, 79,131,201,217,213, 65,190,148,226,180, +103, 39,222,240,128,177, 50, 53,109, 69, 33, 18, 44, 13,244, 56, + 6,155, 88, 26,143,121,233,112,208,194,173,168, 80,117,132, 72, +202,252,218,138,214, 84, 66, 36,191,152,149,249,227, 94,181, 21, +104, 97, 40,186,223, 76,241, 47,129,230,178, 63, 51,238, 54, 16, +110, 24, 70,166, 34,136, 19,247, 45,184, 14, 61,245,164, 57, 59, + 7,158,156,157, 89,159, 27, 8,144, 9,122, 28,234,160,113, 90, +209, 29,195,123,174, 10,169,145, 81, 91,118,114,133,161, 73,235, +203,124,253,196,219, 30,139,210,215,146, 85,170, 67, 11, 37,175, +192,115,153,119,150, 92,250, 82,228,236, 95, 74,182,162, 22,134, +105,197, 98,254, 41,125,187,204,224,211, 77,140,242, 31, 48,220, +130,171,231, 86,179,147, 64,216, 52,176,239, 38, 55, 12, 17, 68, +111,120, 25,154, 71,116,167,193, 35, 83,137,251, 20, 93,248,151, + 46, 75,185, 96, 15,237, 62,229,246,135,165, 23, 58,163, 60,183, +}; + +// Only half the coefficients are given here because the +// generator polynomial is palindromic; G0 = G32, G1 = G31, etc. +// Only G16 is unique +static unsigned char CCSDS_poly[] = { + 0,249, 59, 66, 4, 43,126,251, 97, 30, 3,213, 50, 66,170, 5, + 24, +}; + + +static inline int modnn(int x){ + while (x >= NN) { + x -= NN; + x = (x >> 8) + (x & NN); + } + return x; +} + + +// Update Reed-Solomon encoder +// parity -> 32-byte reed-solomon encoder state; clear this to zero before each frame +void update_rs( + unsigned char parity[32], // 32-byte encoder state; zero before each frame + unsigned char c) // Current data byte to update +{ + unsigned char feedback; + int j,t; + + assert(parity != NULL); + feedback = CCSDS_index_of[c ^ parity[0]]; + if(feedback != A0){ // only if feedback is non-zero + // Take advantage of palindromic polynomial to halve the multiplies + // Do G1...G15, which is the same as G17...G31 + for(j=1;j0) + { buf = word & 0xff; + fwrite(&buf, 1,1, wav_file); + num_bytes--; + word >>= 8; + } +} + +/* information about the WAV file format from + +http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ + + */ + +void write_wav(char * filename, unsigned long num_samples, short int * data, int s_rate) +{ + FILE* wav_file; + unsigned int sample_rate; + unsigned int num_channels; + unsigned int bytes_per_sample; + unsigned int byte_rate; + unsigned long i; /* counter for samples */ + + num_channels = 1; /* monoaural */ + bytes_per_sample = 2; + + if (s_rate<=0) sample_rate = 44100; + else sample_rate = (unsigned int) s_rate; + + byte_rate = sample_rate*num_channels*bytes_per_sample; + + wav_file = fopen(filename, "w"); + assert(wav_file); /* make sure it opened */ + + /* write RIFF header */ + fwrite("RIFF", 1, 4, wav_file); + write_little_endian(36 + bytes_per_sample* num_samples*num_channels, 4, wav_file); + fwrite("WAVE", 1, 4, wav_file); + + /* write fmt subchunk */ + fwrite("fmt ", 1, 4, wav_file); + write_little_endian(16, 4, wav_file); /* SubChunk1Size is 16 */ + write_little_endian(1, 2, wav_file); /* PCM is format 1 */ + write_little_endian(num_channels, 2, wav_file); + write_little_endian(sample_rate, 4, wav_file); + write_little_endian(byte_rate, 4, wav_file); + write_little_endian(num_channels*bytes_per_sample, 2, wav_file); /* block align */ + write_little_endian(8*bytes_per_sample, 2, wav_file); /* bits/sample */ + + /* write data subchunk */ + fwrite("data", 1, 4, wav_file); + write_little_endian(bytes_per_sample* num_samples*num_channels, 4, wav_file); + + for (i=0; i< num_samples; i++) + { write_little_endian((unsigned int)(data[i]),bytes_per_sample, wav_file); + } + + fclose(wav_file); +} + + + +//int main(int argc, char * argv[]) +//{ + +// return 0; +//} + +void write_wave(int i) +{ + if (FSK) + { +// if ((ctr - flip_ctr) < smaller) +// buffer[ctr++] = 0.1 * phase * (ctr - flip_ctr) / smaller; +// else + buffer[ctr++] = 0.25 * amplitude * phase; + } + else + { + if ((ctr - flip_ctr) < smaller) + buffer[ctr++] = (int)(amplitude * 0.4 * phase * + sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + else + buffer[ctr++] = (int)(amplitude * phase * + sin((float)(2*M_PI*i*freq_Hz/S_RATE))); + } +// printf("%d %d \n", i, buffer[ctr - 1]); + +} + +/** + * + * FOX 1 Telemetry Decoder + * @author chris.e.thompson g0kla/ac2cz + * + * Copyright (C) 2015 amsat.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General 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 License for more details. + * + * You should have received a copy of the GNU General License + * along with this program. If not, see . + * + * + * Static variables and methods to encode and decode 8b10b + * + * + */ + +int encodeA(short int *b, int index, int val) { +// printf("Encoding A\n"); + b[index] = val & 0xff; + b[index + 1] = (b[index + 1] & 0xf0) | ((val >> 8) & 0x0f); + return 0; +} + +int encodeB(short int *b, int index, int val) { +// printf("Encoding B\n"); + b[index] = (b[index] & 0x0f) | ((val << 4) & 0xf0); + b[index + 1] = (val >> 4 ) & 0xff; + return 0; +} + +int twosToInt(int val,int len) { // Convert twos compliment to integer +// from https://www.raspberrypi.org/forums/viewtopic.php?t=55815 + + if(val & (1 << (len - 1))) + val = val - (1 << len); + + return(val); +} diff --git a/afsk/make_wav.h b/afsk/make_wav.h new file mode 100644 index 00000000..4b78c660 --- /dev/null +++ b/afsk/make_wav.h @@ -0,0 +1,562 @@ +/* make_wav.h + * Fri Jun 18 17:06:02 PDT 2010 Kevin Karplus + */ + +#ifndef MAKE_WAV_H +#define MAKE_WAV_H + +void write_wav(char * filename, unsigned long num_samples, short int * data, int s_rate); + /* open a file named filename, write signed 16-bit values as a + monoaural WAV file at the specified sampling rate + and close the file + */ + +#endif + +/* + * TelemEncoding.h + * + * Created on: Feb 3, 2014 + * Author: fox + */ + +#ifndef TELEMENCODING_H_ +#define TELEMENCODING_H_ + +void update_rs( + unsigned char parity[32], // 32-byte encoder state; zero before each frame + unsigned char c // Current data byte to update +); + +#define CHARACTER_BITS 10 +#define CHARACTERS_PER_LONGWORD 3 +#define CHARACTER_MASK ((1<. + * + * INA219 Raspberry Pi wiringPi code is based on Adafruit Arduino wire code + * from https://github.com/adafruit/Adafruit_INA219. + */ + +#include +#include +#include +#include +#include +#include "status.h" +#include "ax5043.h" +#include "ax25.h" +#include "spi/ax5043spi.h" +#include +#include +#include +#include +#include "Adafruit_INA219.h" // From Adafruit INA219 library for Arduino + +#define A 1 +#define B 2 +#define C 3 +#define D 4 + +#define PLUS_X 0 +#define PLUS_Y 1 +#define PLUS_Z 2 +#define BAT 3 +#define MINUS_X 4 +#define MINUS_Y 5 +#define MINUS_Z 6 +#define BUS 7 +#define OFF -1 + +int twosToInt(int val, int len); + +struct SensorConfig { + int fd; + uint16_t config; + int calValue; + int powerMultiplier; + int currentDivider; +}; + +struct SensorData { + double current; + double voltage; + double power; +}; + +/** + * @brief Read the data from one of the i2c current sensors. + * + * Reads the current data from the requested i2c current sensor configuration and + * stores it into a SensorData struct. An invalid file descriptor (i.e. less than zero) + * results in a SensorData struct being returned that has both its #current and #power members + * set to NAN. + * + * @param sensor A structure containing sensor configuration including the file descriptor. + * @return struct SensorData A struct that contains the current, voltage, and power readings + * from the requested sensor. + */ +struct SensorData read_sensor_data(struct SensorConfig sensor) { + struct SensorData data = { + .current = 0, + .voltage = 0, + .power = 0 }; + + if (sensor.fd < 0) { + return data; + } + // doesn't read negative currents accurately, shows -0.1mA + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CONFIG, sensor.config); + wiringPiI2CWriteReg16(sensor.fd, INA219_REG_CALIBRATION, sensor.calValue); + delay(1); + int value = wiringPiI2CReadReg16(sensor.fd, INA219_REG_CURRENT); + if (value == -1) + { + sensor.fd = -1; + return data; + } + data.current = (float) twosToInt(value, 16) / (float) sensor.currentDivider; + + wiringPiI2CWrite(sensor.fd, INA219_REG_BUSVOLTAGE); + delay(1); // Max 12-bit conversion time is 586us per sample + value = (wiringPiI2CRead(sensor.fd) << 8 ) | wiringPiI2CRead (sensor.fd); + data.voltage = ((float)(value >> 3) * 4) / 1000; + // power has very low resolution, seems to step in 512mW values + delay(1); + data.power = (float) wiringPiI2CReadReg16(sensor.fd, INA219_REG_POWER) * (float) sensor.powerMultiplier; + + return data; +} + +/** + * @brief Configures an i2c current sensor. + * + * Calculates the configuration values of the i2c sensor so that + * current, voltage, and power can be read using read_sensor_data. + * Supports 16V 400mA and 16V 2.0A settings. + * + * @param sensor A file descriptor that can be used to read from the sensor. + * @param milliAmps The mA configuration, either 400mA or 2A are supported. + * @return struct SensorConfig A struct that contains the configuraton of the sensor. + */ +//struct SensorConfig config_sensor(int sensor, int milliAmps) { +struct SensorConfig config_sensor(char *bus, int address, int milliAmps) { + struct SensorConfig data; + + if (access(bus, W_OK | R_OK) < 0) { // Test if I2C Bus is missing + printf("ERROR: %s bus not present \n", bus); + data.fd = OFF; + return (data); + } + + data.fd = wiringPiI2CSetupInterface(bus, address); + + data.config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_1_40MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_1S_532US | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + if (milliAmps == 400) { // INA219 16V 400mA configuration + data.calValue = 8192; + data.powerMultiplier = 1; + data.currentDivider = 20; // 40; in Adafruit config + } + else { // INA219 16V 2A configuration + data.calValue = 40960; + data.powerMultiplier = 2; + data.currentDivider = 10; // 20; in Adafruit config + } + + //#ifdef DEBUG_LOGGING +// printf("Sensor %s %x configuration: %d %d %d %d %d\n", bus, address, data.fd, +// data.config, data.calValue, data.currentDivider, data.powerMultiplier); +// printf("Sensor %s %x | ", bus, address); + //#endif + return data; +} + +struct SensorConfig sensorV; +struct SensorData readingV; +struct SensorConfig tempSensor; +struct SensorConfig sensor[8]; // 8 current sensors in Solar Power PCB vB4/5 +struct SensorData reading[8]; // 8 current sensors in Solar Power PCB vB4/5 + + +int main(int argc, char *argv[]) { + + if (argc > 1) { + ; + } + + wiringPiSetup (); + + printf("\n"); + + pinMode (2, INPUT); + pullUpDnControl (2, PUD_UP); + + if (digitalRead(2) != HIGH) + { + printf("vB3 with TFB Present\n"); + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); } + else + { + pinMode (3, INPUT); + pullUpDnControl (3, PUD_UP); + + if (digitalRead(3) != HIGH) + { + printf("vB4 Present\n"); + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x44, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x45, 400); + } + else + { + pinMode (26, INPUT); + pullUpDnControl (26, PUD_UP); + + if (digitalRead(26) != HIGH) + { + printf("vB5 Present\n"); + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-3", 0x40, 400); + sensor[MINUS_X] = config_sensor("/dev/i2c-3", 0x41, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-3", 0x44, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-3", 0x45, 400); + } + else + { + printf("VB3 Present\n"); + sensor[PLUS_X] = config_sensor("/dev/i2c-1", 0x40, 400); + sensor[PLUS_Y] = config_sensor("/dev/i2c-1", 0x41, 400); + sensor[PLUS_Z] = config_sensor("/dev/i2c-1", 0x44, 400); + sensor[BAT] = config_sensor("/dev/i2c-1", 0x45, 400); + sensor[BUS] = config_sensor("/dev/i2c-1", 0x4a, 2000); + sensor[MINUS_X] = config_sensor("/dev/i2c-0", 0x40, 400); + sensor[MINUS_Y] = config_sensor("/dev/i2c-0", 0x41, 400); + sensor[MINUS_Z] = config_sensor("/dev/i2c-0", 0x44, 400); } + } + } + +// Reading I2C voltage and current sensors + int count; + for (count = 0; count < 8; count++) + { + reading[count] = read_sensor_data(sensor[count]); +// printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// count, reading[count].voltage, reading[count].current, reading[count].power); + } + printf("\n"); + +// sensorV = config_sensor("/dev/i2c-1", 0x40, 400); +// readingV = read_sensor_data(sensorV); + printf("+X | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// PLUS_X, readingV.voltage, readingV.current, readingV.power); + PLUS_X, reading[PLUS_X].voltage, reading[PLUS_X].current, reading[PLUS_X].power); + +// sensorV = config_sensor("/dev/i2c-1", 0x41, 400); +// readingV = read_sensor_data(sensorV); + printf("+Y | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// PLUS_Y, readingV.voltage, readingV.current, readingV.power); + PLUS_Y, reading[PLUS_Y].voltage, reading[PLUS_Y].current, reading[PLUS_Y].power); + + //sensorV = config_sensor("/dev/i2c-0", 0x40, 400); + //readingV = read_sensor_data(sensorV); + printf("+Z | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// PLUS_Z, readingV.voltage, readingV.current, readingV.power); + PLUS_Z, reading[PLUS_Z].voltage, reading[PLUS_Z].current, reading[PLUS_Z].power); + +// sensorV = config_sensor("/dev/i2c-0", 0x41, 400); +// readingV = read_sensor_data(sensorV); + printf("-X | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// MINUS_X, readingV.voltage, readingV.current, readingV.power); + MINUS_X, reading[MINUS_X].voltage, reading[MINUS_X].current, reading[MINUS_X].power); + +// sensorV = config_sensor("/dev/i2c-0", 0x44, 400); +// readingV = read_sensor_data(sensorV); + printf("-Y | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// MINUS_Y, readingV.voltage, readingV.current, readingV.power); + MINUS_Y, reading[MINUS_Y].voltage, reading[MINUS_Y].current, reading[MINUS_Y].power); + +//sensorV = config_sensor("/dev/i2c-0", 0x45, 400); +// readingV = read_sensor_data(sensorV); + printf("-Z | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// MINUS_Z, readingV.voltage, readingV.current, readingV.power); + MINUS_Z, reading[MINUS_Z].voltage, reading[MINUS_Z].current, reading[MINUS_Z].power); + +// sensorV = config_sensor("/dev/i2c-1", 0x45, 400); +// readingV = read_sensor_data(sensorV); + printf("Bat | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// BAT, readingV.voltage, readingV.current, readingV.power); + BAT, reading[BAT].voltage, reading[BAT].current, reading[BAT].power); + + // sensorV = config_sensor("/dev/i2c-1", 0x44, 400); + // readingV = read_sensor_data(sensorV); + printf("Bus | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n", +// BUS, readingV.voltage, readingV.current, readingV.power); + BUS, reading[BUS].voltage, reading[BUS].current, reading[BUS].power); + + /* + sensorV = config_sensor("/dev/i2c-3", 0x48, 0); + if (sensorV.fd != OFF) { + int tempValue = wiringPiI2CReadReg16(sensorV.fd, 0); + uint8_t upper = (uint8_t) (tempValue >> 8); + uint8_t lower = (uint8_t) (tempValue & 0xff); + float temp = (float)lower + ((float)upper / 0x100); + printf("T | % 4.1f C \n", temp); + } + */ + + printf("\n\n"); + + return 0; +} + +int twosToInt(int val,int len) { // Convert twos compliment to integer +// from https://www.raspberrypi.org/forums/viewtopic.php?t=55815 + + if(val & (1 << (len - 1))) + val = val - (1 << len); + + return(val); +} diff --git a/amsat.wav b/amsat.wav new file mode 100644 index 00000000..ecbe6fa7 Binary files /dev/null and b/amsat.wav differ diff --git a/amsat_iq.wav b/amsat_iq.wav new file mode 100644 index 00000000..4fb84e27 Binary files /dev/null and b/amsat_iq.wav differ diff --git a/amsat_logo_iq.wav b/amsat_logo_iq.wav new file mode 100644 index 00000000..be2081f3 Binary files /dev/null and b/amsat_logo_iq.wav differ diff --git a/arduino/PayloadOK.ino b/arduino/PayloadOK.ino new file mode 100644 index 00000000..d6514990 --- /dev/null +++ b/arduino/PayloadOK.ino @@ -0,0 +1,28 @@ + // code for STM32F104C on the CubeSat Simulator STEM Payload board + // answers "OK" on the serial port when queried by the Pi + + int counter = 0; + + void setup() { + Serial1.begin(9600); + pinMode(PC13, OUTPUT); + digitalWrite(PC13, LOW); // turn the LED on + delay(50); // wait for a second + digitalWrite(PC13, HIGH); // turn the LED off + +} + +void loop() { + + if (Serial1.available() > 0) { + digitalWrite(PC13, LOW); // turn the LED on + delay(50); // wait for a second + digitalWrite(PC13, HIGH); // turn the LED off + char result = Serial1.read(); +// Serial1.println(result); + Serial1.println("OK"); +// Serial1.println(counter++); + } + + delay(100); +} diff --git a/arduino/README.md b/arduino/README.md index 8114ec41..a7508672 100644 --- a/arduino/README.md +++ b/arduino/README.md @@ -1,12 +1,32 @@ -This code is used on an Arduino acting as a payload to the CubeSat Simulator. +This code is used on the STM32 acting a payload to the CubeSat Simulator. -The Arduino is on the Raspberry Pi i2c bus 0, address 0x4b +The interface is via the Serial1 port on the STM32 (pins PA9 and PA10) and the Raspberry Pi UART (pins 8 and 10) -The 2c_master_register_read.ino code emulates the register reading of the Raspberry Pi. You can connect two Arduinos back-to-back to show this. +The STM32 can be programmed using the Arduino IDE with the Generic STM32F103C series board and STM32duino bootloader, Maple Mini port. -The i2c_slave_register_read.ino code responds to register reads from a bus master such as another Arduino or the Raspberry Pi +On the Raspberry Pi, to enable the UART: -The i2c_slave_with_sensor_reading.ino code responds to register reads from a bus master and has placeholders for reading a sensor. +sudo nano /boot/config.txt + +Add the following line: + +dtoverlay=pi3-miniuart-bt + +Edit cmdline.txt: + +sudo nano /boot/cmdline.txt + +Remove the following text in cmdline.txt to prevent a console from running on the serial port: + +console=serial0,115200 + +then reboot. You can test it with minicom: + +sudo apt-get install minicom + +minicom -b 9600 -o -D /dev/serial0 + +Type Control-A, then X, then Return to exit. See https://github.com/alanbjohnston/CubeSatSim/wiki/Arduino-Payload for ideas on using the Arduino as a payload for the CubeSat Simulator. diff --git a/arduino/i2c_master_register_read.ino b/arduino/i2c_master_register_read.ino deleted file mode 100644 index a2a6f789..00000000 --- a/arduino/i2c_master_register_read.ino +++ /dev/null @@ -1,55 +0,0 @@ -// Wire Master Reader -// by Nicholas Zambetti - -// Demonstrates use of the Wire library -// Reads data from an I2C/TWI slave device -// Refer to the "Wire Slave Sender" example for use with this - -// Created 29 March 2006 - -// This example code is in the public domain. - -// modified by Alan Johnston to show reading registers 0 - 3 -// code based on https://forum.arduino.cc/index.php?topic=211587.0 -// -// This code is to simulate the Raspberry Pi acting as I2C bus master - -#include -#define I2C_ADDRESS 0x4B -#define REGISTER_0 0x00 -#define REGISTER_1 0x01 -#define REGISTER_2 0x02 -#define REGISTER_3 0x03 - -uint8_t reg; // I2C read register - -void setup() { - Wire.begin(); // join i2c bus (address optional for master) - Serial.begin(9600); // start serial for output - pinMode(LED_BUILTIN, OUTPUT); - Serial.println("Starting"); -} - -void loop() { - for (reg=0; reg < 4; reg++) { - delay(5000); - digitalWrite(LED_BUILTIN, HIGH); - Wire.beginTransmission(I2C_ADDRESS); - Wire.write(reg); - Wire.endTransmission(); - delay(100); - digitalWrite(LED_BUILTIN, LOW); - - - Wire.requestFrom(I2C_ADDRESS, 2); // request 2 bytes from I2C device - byte LSB = Wire.read(); - byte MSB = Wire.read(); - - uint16_t register_value = ((MSB << 8) | LSB); - - Serial.print("Read "); - Serial.print(register_value, HEX); // display register value in HEXADECIMAL - Serial.print(" from register "); - Serial.println(reg); - } -} diff --git a/arduino/i2c_slave_register_read.ino b/arduino/i2c_slave_register_read.ino deleted file mode 100644 index 2f033587..00000000 --- a/arduino/i2c_slave_register_read.ino +++ /dev/null @@ -1,75 +0,0 @@ -// Arduino I2C slave for reading 16 bit registers -// -// by Alan Johnston -// -// based on - -#include -#define I2C_ADDRESS 0x4B -#define REGISTER_0 0x00 -#define REGISTER_1 0x01 -#define REGISTER_2 0x02 -#define REGISTER_3 0x03 - -uint8_t reg; // I2C read register - -unsigned int reg_0_value, reg_1_value, reg_2_value, reg_3_value; // register variables - -void setup() { - - Wire.begin(I2C_ADDRESS); - Wire.setClock(400000); // set I2C clock for full speed - digitalWrite(A4, LOW); - digitalWrite(A5, LOW); - Wire.onRequest(requestEvent); - Wire.onReceive(receiveEvent); - pinMode(LED_BUILTIN, OUTPUT); - Serial.begin(9600); // start serial for output - Serial.println(); - Serial.println("Starting"); -} - -void loop() { - Serial.println("Waiting for register read"); - - // Read from sensor here and set register variables - reg_0_value = 57007; // decimal values of registers for testing - reg_1_value = 48879; - reg_2_value = 3790; - reg_3_value = 4613; - - delay(5000); -} - -void receiveEvent(int bytes) { - // Read the first byte to determine which register is concerned - reg = Wire.read(); - Serial.print("Read register "); - Serial.println(reg); -} - -void requestEvent() { - // Read from the register variable to know what to send back - digitalWrite(LED_BUILTIN, HIGH); - if (reg == REGISTER_0) { - Wire.write((uint8_t *)®_0_value, sizeof(reg_0_value)); - Serial.print("Writing value "); - Serial.println(reg_0_value, DEC); // writing register value in DECIMAL format - } else if (reg == REGISTER_1) { - Wire.write((uint8_t *)®_1_value, sizeof(reg_1_value)); - Serial.print("Writing value "); - Serial.println(reg_1_value, DEC); - } else if (reg == REGISTER_2) { - Wire.write((uint8_t *)®_2_value, sizeof(reg_2_value)); - Serial.print("Writing value "); - Serial.println(reg_2_value, DEC); - } else if (reg == REGISTER_3) { - Wire.write((uint8_t *)®_3_value, sizeof(reg_3_value)); - Serial.print("Writing value "); - Serial.println(reg_3_value, DEC); - } else { - Serial.println("Unknown register"); - } - delay(50); - digitalWrite(LED_BUILTIN, LOW); -} diff --git a/arduino/i2c_slave_with_sensor_reading.ino b/arduino/i2c_slave_with_sensor_reading.ino deleted file mode 100644 index c3e97ae1..00000000 --- a/arduino/i2c_slave_with_sensor_reading.ino +++ /dev/null @@ -1,73 +0,0 @@ -#include -#define REGISTER_0 0x00 -#define REGISTER_1 0x01 -#define REGISTER_2 0x02 -#define REGISTER_3 0x03 -#define I2C_ADDRESS_SELF 0x4B - -unsigned int reg_0_value = 41151; -unsigned int reg_1_value = 0; -unsigned int reg_2_value = 0; -unsigned int reg_3_value = 0; - -uint8_t master_reg; // I2C master read register -uint8_t slave_reg; // I2C slave read register - -void setup() -{ - Serial.begin(9600); //Begins Serial communication - Serial.println("Setup for sensor"); - - Wire.begin(I2C_ADDRESS_SELF); // join i2c bus - Wire.setClock(400000); // set I2C clock for full speed - Serial.begin(9600); // start serial for output - digitalWrite(A4, LOW); - digitalWrite(A5, LOW); - Wire.onRequest(requestEvent); - Wire.onReceive(receiveEvent); - pinMode(LED_BUILTIN, OUTPUT); - Serial.println("Starting"); -} - -void loop() -{ - delay(1000); - - Serial.println("Read sensor value"); - - reg_0_value = 1; // set register 0 value to the sensor value - reg_1_value += 1; // increment a count of how many values read -} - -void receiveEvent(int bytes) { - // Slave reads the first byte to determine which register is concerned - slave_reg = Wire.read(); - Serial.print("Slave read register "); - Serial.println(slave_reg); -} - -void requestEvent() { - // Slave uses the the register variable to know what to send back - digitalWrite(LED_BUILTIN, HIGH); - if (slave_reg == REGISTER_0) { - Wire.write((uint8_t *)®_0_value, sizeof(reg_0_value)); - Serial.print("Slave writing value "); - Serial.println(reg_0_value); - } else if (slave_reg == REGISTER_1) { - Wire.write((uint8_t *)®_1_value, sizeof(reg_1_value)); - Serial.print("Slave writing value "); - Serial.println(reg_1_value); - } else if (slave_reg == REGISTER_2) { - Wire.write((uint8_t *)®_2_value, sizeof(reg_2_value)); - Serial.print("Slave writing value "); - Serial.println(reg_2_value); - } else if (slave_reg == REGISTER_3) { - Wire.write((uint8_t *)®_3_value, sizeof(reg_3_value)); - Serial.print("Slave writing value "); - Serial.println(reg_3_value); - } else { - Serial.println("Slave unknown register"); - } - delay(50); - digitalWrite(LED_BUILTIN, LOW); -} diff --git a/demo.sh b/demo.sh index ab39e8ab..2e9c4027 100755 --- a/demo.sh +++ b/demo.sh @@ -1,19 +1,29 @@ #!/bin/bash -echo -e "\nDemo of CubeSatSim sends AFSK telemetry at 440 MHz continuously\n\n" - -sleep 30 - -#echo 'sleep over' >> /home/pi/CubeSatSim/log.txt - -echo $(date '+%Y %b %d %H:%M') Starting Hostname $HOSTNAME >> /home/pi/CubeSatSim/log.txt - -/home/pi/CubeSatSim/radioafsk >> /home/pi/CubeSatSim/log.txt -#/home/pi/DigitalTxRxRPi/testafsktx >> /home/pi/CubeSatSim/log.txt - -echo $(date '+%Y %b %d %H:%M') Stopping Hostname $HOSTNAME >> /home/pi/CubeSatSim/log.txt - -#/home/pi/mopower/mpcmd LED_STAT=0 -#sleep 30 - -#/home/pi/CubeSatSim/configax +echo -e "\nDemo of CubeSatSim at 434.9 MHz\n" + +#exit + +y=$(last reboot | grep ^reboot | wc -l) +echo $y + +if (( $y % 2 == 0 )) +then + echo -e "\n Continuous FSK Mode\n\n" + /home/pi/CubeSatSim/radioafsk f +else + + echo -e "\n Alternating FSK, BPSK, and AFSK telemetry Mode \n\n" + /home/pi/CubeSatSim/radioafsk afsk 5 y + while true; do + echo -e "\n Changing mode ******\n\n" + /home/pi/CubeSatSim/radioafsk fsk 5 n + /home/pi/CubeSatSim/radioafsk bpsk 5 n +# sleep 24 + sleep 1 + sudo killall -9 sendiq + sudo killall -9 sendiq + sleep 1 + /home/pi/CubeSatSim/radioafsk afsk 5 n + done +fi diff --git a/demo2.sh b/demo2.sh new file mode 100755 index 00000000..51f0284f --- /dev/null +++ b/demo2.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +echo -e "\nDemo of CubeSatSim sends AFSK telemetry at 434.9 MHz continuously\n\n" + +#exit + +sudo killall -9 rpitx +sudo killall -9 sendiq +sudo fuser -k 8080/tcp + +/home/pi/CubeSatSim/radioafsk a 3 diff --git a/fox-demo.sh b/fox-demo.sh new file mode 100755 index 00000000..2810ee4f --- /dev/null +++ b/fox-demo.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +echo -e "\nDemo of CubeSatSim sends FSK, BPSK, and AFSK telemetry alternately at 434.9 MHz continuously\n\n" + +sudo killall -9 rpitx +sudo killall -9 sendiq +sudo fuser -k 8080/tcp + +while true; do + sleep 1; + echo -e "\n Changing mode ********************************************************************************\n\n" + + timeout 25 /home/pi/CubeSatSim/radioafsk c 3 + sudo killall -9 rpitx + sudo killall -9 sendiq + sudo fuser -k 8080/tcp +done diff --git a/happy_easter.wav b/happy_easter.wav new file mode 100644 index 00000000..37788e07 Binary files /dev/null and b/happy_easter.wav differ diff --git a/happy_easter2.wav b/happy_easter2.wav new file mode 100644 index 00000000..7d5a88dc Binary files /dev/null and b/happy_easter2.wav differ diff --git a/picture2.wav b/picture2.wav new file mode 100644 index 00000000..51912fb7 Binary files /dev/null and b/picture2.wav differ diff --git a/python/telem.py b/python/telem.py index 283a5882..ac921207 100644 --- a/python/telem.py +++ b/python/telem.py @@ -14,10 +14,18 @@ ina44p = 0 ina45v = 0 ina45i = 0 ina45p = 0 -ina4av = 0 -ina4ai = 0 -ina4ap = 0 - +ina403v = 0 +ina403i = 0 +ina403p = 0 +ina413v = 0 +ina413i = 0 +ina413p = 0 +ina443v = 0 +ina443i = 0 +ina443p = 0 +ina453v = 0 +ina453i = 0 +ina453p = 0 FAIL = -1 try: @@ -75,21 +83,57 @@ if INA219DISABLE !=1: except: FAIL = 1 try: - ina4a = INA219(SHUNT_OHMS, MAX_EXPECTED_AMPS, 0x4a) - ina4a.wake(); - ina4a.configure(ina4a.RANGE_16V) - ina4a.busnum = 1; - ina4av = ina4a.voltage() - ina4ai = ina4a.current() - ina4ap = ina4a.power() - ina4a.sleep(); + ina403 = INA219(SHUNT_OHMS45, MAX_EXPECTED_AMPS45, 0x40) + ina403.wake(); + ina403.configure(ina403.RANGE_16V) + ina403.busnum = 3; + ina403v = ina403.voltage() + ina403i = ina403.current() + ina403p = ina403.power() + ina403.sleep(); + except: + FAIL = 1 + try: + ina413 = INA219(SHUNT_OHMS45, MAX_EXPECTED_AMPS45, 0x41) + ina413.wake(); + ina413.configure(ina413.RANGE_16V) + ina413.busnum = 3; + ina413v = ina413.voltage() + ina413i = ina413.current() + ina413p = ina413.power() + ina413.sleep(); + except: + FAIL = 1 + try: + ina443 = INA219(SHUNT_OHMS45, MAX_EXPECTED_AMPS45, 0x44) + ina443.wake(); + ina443.configure(ina443.RANGE_16V) + ina443.busnum = 3; + ina443v = ina443.voltage() + ina443i = ina443.current() + ina443p = ina443.power() + ina443.sleep(); + except: + FAIL = 1 + try: + ina453 = INA219(SHUNT_OHMS45, MAX_EXPECTED_AMPS45, 0x45) + ina453.wake(); + ina453.configure(ina453.RANGE_16V) + ina453.busnum = 3; + ina453v = ina453.voltage() + ina453i = ina453.current() + ina453p = ina453.power() + ina453.sleep(); except: FAIL = 1 if INA219DISABLE !=1: print print "+X (0x40) v=",ina40v, "V i=", ina40i, "mA p=", ina40p, "mW " print "+Y (0x41) v=",ina41v, "V i=", ina41i, "mA p=", ina41p, "mW " - print "+Z (0x44) v=",ina44v, "V i=", ina44i, "mA p=", ina44p, "mW " + print "5V Supply (0x44) v=",ina44v, "V i=", ina44i, "mA p=", ina44p, "mW " print "Battery (0x45) v=",ina45v, "V i=", ina45i, "mA p=", ina45p, "mW " - print "5V Supply(0x4a) v=",ina4av, "V i=", ina4ai, "mA p=", ina4ap, "mW " + print "+Z (0x40 3) v=",ina403v, "V i=", ina403i, "mA p=", ina403p, "mW " + print "-X (0x41 3) v=",ina413v, "V i=", ina413i, "mA p=", ina413p, "mW " + print "-Y (0x44 3) v=",ina443v, "V i=", ina443i, "mA p=", ina443p, "mW " + print "-Z (0x45 3) v=",ina453v, "V i=", ina453i, "mA p=", ina453p, "mW " print diff --git a/radio.afsk b/radio.afsk deleted file mode 100755 index e0276c20..00000000 Binary files a/radio.afsk and /dev/null differ diff --git a/radio.cw b/radio.cw deleted file mode 100755 index f101a012..00000000 Binary files a/radio.cw and /dev/null differ diff --git a/radio.cw.once b/radio.cw.once deleted file mode 100755 index d9aac187..00000000 Binary files a/radio.cw.once and /dev/null differ diff --git a/smiley.iq b/smiley.iq new file mode 100644 index 00000000..9b1860ee Binary files /dev/null and b/smiley.iq differ diff --git a/smileysox.wav b/smileysox.wav new file mode 100644 index 00000000..3c79dbe9 Binary files /dev/null and b/smileysox.wav differ diff --git a/socket/data.txt b/socket/data.txt new file mode 100644 index 00000000..555b8c12 --- /dev/null +++ b/socket/data.txt @@ -0,0 +1,5 @@ +20:51:55$ fm KU2Y-1 to CQ-1 UI PID=F0 +hi hi 113 199 199 199 299 299 299 249 326 350 300 300 444 400 400 400 500 500 500 500 600 600 600 650 +20:51:55$ fm KU2Y-1 to CQ-1 UI PID=F0 +hi hi 114 199 199 199 299 299 299 249 326 350 300 300 444 400 400 400 500 500 500 500 600 600 600 650 + diff --git a/spacecraft/FoxTelem Files.zip b/spacecraft/FoxTelem Files.zip new file mode 100644 index 00000000..2a4c0d18 Binary files /dev/null and b/spacecraft/FoxTelem Files.zip differ diff --git a/spacecraft/FoxTelem_1.09b/CubeSatSim_rttelemetryFM.csv b/spacecraft/FoxTelem_1.09b/CubeSatSim_rttelemetryFM.csv new file mode 100644 index 00000000..a84c5f45 --- /dev/null +++ b/spacecraft/FoxTelem_1.09b/CubeSatSim_rttelemetryFM.csv @@ -0,0 +1,45 @@ +44,TYPE,FIELD,BITS,UNIT,CONVERSION,MODULE,MODULE_NUM,MODULE_LINE,LINE_TYPE,SHORT_NAME,DESCRIPTION +0,RT,BATT_A_V,12,V,4,NONE,0,0,3,Cell A,Battery pair A voltage (0-2.5V scale) +1,RT,BATT_B_V,12,V,4,NONE,0,0,3,Cell A + B,Battery pairs A+B voltage (0-3.3V scale) +2,RT,BATT_V,12,V,4,Battery,3,1,3,Battery Voltage,Battery pairs A+B+C voltage (0-5.0V scale) +3,RT,BATT_A_T,12,C,8,NONE,0,0,3,Temperature A,Battery pair A temperature +4,RT,BATT_B_T,12,C,8,NONE,0,0,3,Temperature B,Battery pair B temperature +5,RT,BATT_C_T,12,C,8,NONE,0,0,3,Temperature C,Battery pair C temperature +6,RT,TOTAL_BATT_I,12,mA,4,Battery,3,2,3,Current,Total Battery DC current +7,RT,BATTBoardTemperature,12,C,8,NONE,0,0,3,Board Temp,Battery Card Temperature +8,RT,PANEL_PLUS_X_V,12,V,5,+X Panel,6,2,3,Voltage,+X Panel +9,RT,PANEL_MINUS_X_V,12,V,5,-X Panel,9,2,3,Voltage,-X Panel +10,RT,PANEL_PLUS_Y_V,12,V,5,+Y Panel,7,2,3,Voltage,+YPanel +11,RT,PANEL_MINUS_Y_V,12,V,5,-Y Panel,10,2,3,Voltage,-Y Panel +12,RT,PANEL_PLUS_Z_V,12,V,5,+Z Panel,8,2,3,Voltage,+Z Panel +13,RT,PANEL_MINUS_Z_V,12,V,5,-Z Panel,11,2,3,Voltage,-Z Panel +14,RT,PANEL_PLUS_X_I,12,mA,4,+X Panel,6,1,3,Current,+X Panel +15,RT,PANEL_MINUS_X_I,12,mA,4,-X Panel,9,1,3,Current,-X Panel +16,RT,PANEL_PLUS_Y_I,12,mA,4,+Y Panel,7,1,3,Current,+Y Panel +17,RT,PANEL_MINUS_Y_I,12,mA,4,-Y Panel,10,1,3,Current,-Y Panel +18,RT,PANEL_PLUS_Z_I,12,mA,4,+Z Panel,8,1,3,Current,+Z Panel +19,RT,PANEL_MINUS_Z_I,12,mA,4,-Z Panel,11,1,3,Current,-Z Panel +20,RT,PSUTemperature,12,C,7,PSU,4,2,3,Board Temp,Power Supply Card Temperature +21,RT,SPIN,12,rpm,12,Computer,2,2,3,Spacecraft Spin,Calculated spin rate using solar cells +22,RT,TXPACurrent,12,mA,10,NONE,1,0,3,PA Current,Transmit power amplifier current +23,RT,TXTemperature,12,C,7,NONE,1,0,3,TX Temperature,Transmitter card temperature +24,RT,RXTemperature,12,C,7,Radio,1,1,3,RX Temperature,Receiver card temperature +25,RT,RSSI,12,dBm,14,Radio,1,2,3,RSSI,Received Signal Strength Indication +26,RT,IHUTemperature,12,C,15,Computer,2,1,3,Temperature,Internal Temperature of IHU +27,RT,SatelliteXAxisAngularVelocity,12,dps,13,+X Panel,6,3,3,Rotation,Angular Veolcity around X Axis +28,RT,SatelliteYAxisAngularVelocity,12,dps,13,+Y Panel,7,3,3,Rotation,Angular Veolcity around Y Axis +29,RT,SatelliteZAxisAngularVelocity,12,dps,13,+Z Panel,8,3,3,Rotation,Angular Veolcity around Z Axis +30,RT,EXP4Temperature,12,C,7,NONE,5,0,0,EXP4 Temperature,Not used +31,RT,PSUCurrent,12,mA,11,PSU,4,1,3,Current,Power Supply DC Current +32,RT,IHUDiagnosticData,32,-,18,Computer,2,7,0,Diagnostic Info,Diagnostic Data on IHU Performance +33,RT,Experiment1FailureIndication,1,-,17,Experiments,5,1,0,Vanderbilt Radiation,Vanderbilt University Vulcan Experiment Indicator +34,RT,Experiment2FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +35,RT,Experiment3FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +36,RT,Experiment4FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +37,RT,BATTI2CFailureIndications,1,-,17,Computer,2,3,0,Battery I2C,Battery I2C Bus failure indicator +38,RT,PSU1I2CFailureIndications,1,-,17,Computer,2,4,0,PSU1 I2C,PSU2 I2C Bus failure indicator +39,RT,PSU2I2CFailureIndications,1,-,17,Computer,2,5,0,PSU2 I2C,PSU2 I2C Bus failure indicator +40,RT,NumberofGroundCommandedTLMResets,4,-,1,Computer,2,6,0,Ground Resets,Number of times command stations reset stored telemetry +41,RT,RXAntenna,1,-,16,Radio,1,4,0,RX Antenna,70cm Antenna status +42,RT,TXAntenna,1,-,16,Radio,1,3,0,TX Antenna,2m Antenna status +43,RT,Pad,51,-,0,NONE,0,0,0,NONE,NONE diff --git a/spacecraft/FoxTelem_1.09b/CubeSat_Simulator_BPSK_fm.MASTER b/spacecraft/FoxTelem_1.09b/CubeSat_Simulator_BPSK_fm.MASTER new file mode 100644 index 00000000..db939588 --- /dev/null +++ b/spacecraft/FoxTelem_1.09b/CubeSat_Simulator_BPSK_fm.MASTER @@ -0,0 +1,69 @@ +#Fox 1 Telemetry Decoder Properties +#Sat Oct 12 10:34:00 EST 2019 +user_mode=4 +foxId=99 +IHU_SN=7 +catalogNumber=0 +model=1 +mpptResistanceError=6.58 +mpptSensorOffThreshold=1600 +name=CubeSat Simulator BPSK +displayName=CubeSat Simulator BPSK +BATTERY_CURRENT_ZERO=-1.834 +hasImprovedCommandReceiver=true +EXP1=6 +EXP2=1 +EXP3=8 +EXP4=7 +description=The AMSAT CubeSat Simulator is a functional model of a 1U CubeSat, for more info see http://cubesatsim.org +numberOfFrameLayouts=5 +frameLayout0.filename=FOX1E_Type0_ALL_WOD.frame +frameLayout0.name=All WOD +frameLayout1.filename=FOX1E_Type1_HEALTH.frame +frameLayout1.name=Health +frameLayout2.filename=FOX1E_Type2_MINMAX.frame +frameLayout2.name=MinMax +frameLayout3.filename=FOX1E_Type3_REALTIME_BEACON.frame +frameLayout3.name=Realtime Beacon +frameLayout4.filename=FOX1E_Type4_WOD_BEACON.frame +frameLayout4.name=WOD Beacon +numberOfLayouts=9 +layout0.filename=FOX1A_debug.csv +layout0.name=DEBUG +layout1.filename=FOX1E_maxtelemetry.csv +layout1.name=maxtelemetry +layout2.filename=FOX1E_rttelemetry.csv +layout2.name=rttelemetry +layout3.filename=FOX1E_mintelemetry.csv +layout3.name=mintelemetry +layout4.filename=FOX1E_radtelemetry.csv +layout4.name=radtelemetry +layout5.filename=FOX1E_radtelemetry2.csv +layout5.name=radtelemetry2 +layout5.parentLayout=radtelemetry +layout6.filename=FOX1E_wodtelemetry.csv +layout6.name=wodtelemetry +layout7.filename=FOX1E_wodradtelemetry.csv +layout7.name=wodradtelemetry +layout8.filename=FOX1E_wodradtelemetry2.csv +layout8.name=wodradtelemetry2 +layout8.parentLayout=wodradtelemetry +numberOfLookupTables=3 +lookupTable0.filename=FOX1A_rssiFM.tab +lookupTable0=RSSI +lookupTable1.filename=FOX1E_ihuVBattSNx.tab +lookupTable1=IHU_VBATT +lookupTable2.filename=FOX1A_ihutempSN7.tab +lookupTable2=IHU_TEMP +maxFreqBoundkHz=434950 +measurementsFileName=measurements.csv +memsRestValueX=2129 +memsRestValueY=2131 +memsRestValueZ=2103 +minFreqBoundkHz=434850 +passMeasurementsFileName=passmeasurements.csv +telemetryDownlinkFreqkHz=434900 +track=false +useIHUVBatt=false +numberOfSources=1 +source0.name=ihu.bpsk diff --git a/spacecraft/FoxTelem_1.09b/CubeSat_Simulator_FSK_fm.MASTER b/spacecraft/FoxTelem_1.09b/CubeSat_Simulator_FSK_fm.MASTER new file mode 100644 index 00000000..a57b2188 --- /dev/null +++ b/spacecraft/FoxTelem_1.09b/CubeSat_Simulator_FSK_fm.MASTER @@ -0,0 +1,51 @@ +#Fox 1 Telemetry Decoder Properties +#Sat Oct 12 10:35:00 EST 2019 +#File named .dat should be in the logfiles directory and is loaded by FoxTelem +#File named .MASTER should not be edited and is a backup copy in the installation directory +foxId=7 +displayName=CubeSat Simulator FSK +name=CubeSat Simulator FSK +model=1 +IHU_SN=7 +catalogNumber=0 +description=The AMSAT CubeSat Simulator is a functional model of a 1U CubeSat, for more info see http://cubesatsim.org +BATTERY_CURRENT_ZERO=-1.839 +EXP1=6 +EXP2=1 +EXP3=0 +EXP4=0 +numberOfLayouts=6 +layout0.filename=FOX1A_debug.csv +layout0.name=DEBUG +layout1.filename=FOX1A_maxtelemetry.csv +layout1.name=maxtelemetry +layout2.filename=CubeSatSim_rttelemetryFM.csv +layout2.name=rttelemetry +layout3.filename=FOX1A_mintelemetry.csv +layout3.name=mintelemetry +layout4.filename=FOX1A_radtelemetry.csv +layout4.name=radtelemetry +layout5.filename=FOX1A_radtelemetry2.csv +layout5.name=radtelemetry2 +layout5.parentLayout=radtelemetry +lookupTable0.filename=FOX1A_rssiFM.tab +numberOfLookupTables=3 +lookupTable0=RSSI +lookupTable1.filename=FOX1A_ihuVBattSN7.tab +lookupTable1=IHU_VBATT +lookupTable2.filename=FOX1A_ihutempSN7.tab +lookupTable2=IHU_TEMP +telemetryDownlinkFreqkHz=434900 +maxFreqBoundkHz=434950 +minFreqBoundkHz=434850 +measurementsFileName=measurements.csv +memsRestValueX=2087 +memsRestValueY=2101 +memsRestValueZ=2045 +passMeasurementsFileName=passmeasurements.csv +numberOfSources=2 +source0.name=ihu.duv +source1.name=ihu.highspeed +track=true +useIHUVBatt=true +user_mode=0 diff --git a/spacecraft/FoxTelem_1.09f/CubeSatSim_rttelemetryFM.csv b/spacecraft/FoxTelem_1.09f/CubeSatSim_rttelemetryFM.csv new file mode 100644 index 00000000..a134f759 --- /dev/null +++ b/spacecraft/FoxTelem_1.09f/CubeSatSim_rttelemetryFM.csv @@ -0,0 +1,45 @@ +44,TYPE,FIELD,BITS,UNIT,CONVERSION,MODULE,MODULE_NUM,MODULE_LINE,LINE_TYPE,SHORT_NAME,DESCRIPTION +0,RT,BATT_A_V,12,V,4,NONE,0,0,3,Cell A,Battery pair A voltage (0-2.5V scale) +1,RT,BATT_B_V,12,V,4,NONE,0,0,3,Cell A + B,Battery pairs A+B voltage (0-3.3V scale) +2,RT,BATT_V,12,V,cubesatsim_ina219_voltage,Battery,3,1,3,Cell A + B + C,Battery A+B+C voltage (0-5.0V scale) +3,RT,BATT_A_T,12,C,8,NONE,0,0,3,Temperature A,Battery pair A temperature +4,RT,BATT_B_T,12,C,8,NONE,0,0,3,Temperature B,Battery pair B temperature +5,RT,BATT_C_T,12,C,8,NONE,0,0,3,Temperature C,Battery pair C temperature +6,RT,TOTAL_BATT_I,12,mA,cubesatsim_ina219_current,Battery,3,2,3,Current,Total Battery DC current +7,RT,BATTBoardTemperature,12,C,8,NONE,0,0,3,Board Temp,Battery Card Temperature +8,RT,PANEL_PLUS_X_V,12,V,cubesatsim_ina219_voltage,+X Panel,6,2,3,Voltage,+X Panel +9,RT,PANEL_MINUS_X_V,12,V,cubesatsim_ina219_voltage,-X Panel,9,2,3,Voltage,-X Panel +10,RT,PANEL_PLUS_Y_V,12,V,cubesatsim_ina219_voltage,+Y Panel,7,2,3,Voltage,+YPanel +11,RT,PANEL_MINUS_Y_V,12,V,cubesatsim_ina219_voltage,-Y Panel,10,2,3,Voltage,-Y Panel +12,RT,PANEL_PLUS_Z_V,12,V,cubesatsim_ina219_voltage,+Z Panel,8,2,3,Voltage,+Z Panel +13,RT,PANEL_MINUS_Z_V,12,V,cubesatsim_ina219_voltage,-Z Panel,11,2,3,Voltage,-Z Panel +14,RT,PANEL_PLUS_X_I,12,mA,cubesatsim_ina219_current,+X Panel,6,1,3,Current,+X Panel +15,RT,PANEL_MINUS_X_I,12,mA,cubesatsim_ina219_current,-X Panel,9,1,3,Current,-X Panel +16,RT,PANEL_PLUS_Y_I,12,mA,cubesatsim_ina219_current,+Y Panel,7,1,3,Current,+Y Panel +17,RT,PANEL_MINUS_Y_I,12,mA,cubesatsim_ina219_current,-Y Panel,10,1,3,Current,-Y Panel +18,RT,PANEL_PLUS_Z_I,12,mA,cubesatsim_ina219_current,+Z Panel,8,1,3,Current,+Z Panel +19,RT,PANEL_MINUS_Z_I,12,mA,cubesatsim_ina219_current,-Z Panel,11,1,3,Current,-Z Panel +20,RT,PSUVoltage,12,V,cubesatsim_ina219_voltage,PSU,4,2,3,Board Voltage,Power Supply Voltage +21,RT,SPIN,12,rpm,12,Computer,2,2,3,Spacecraft Spin,Calculated spin rate using solar cells +22,RT,TXPACurrent,12,mA,10,NONE,1,0,3,PA Current,Transmit power amplifier current +23,RT,TXTemperature,12,C,7,NONE,1,0,3,TX Temperature,Transmitter card temperature +24,RT,RXTemperature,12,C,7,Radio,1,1,3,RX Temperature,Receiver card temperature +25,RT,RSSI,12,dBm,14,Radio,1,2,3,RSSI,Received Signal Strength Indication +26,RT,IHUTemperature,12,C,cubesatsim_temperature,Computer,2,1,3,Temperature,Internal Temperature of IHU +27,RT,SatelliteXAxisAngularVelocity,12,dps,13,+X Panel,6,3,3,Rotation,Angular Veolcity around X Axis +28,RT,SatelliteYAxisAngularVelocity,12,dps,13,+Y Panel,7,3,3,Rotation,Angular Veolcity around Y Axis +29,RT,SatelliteZAxisAngularVelocity,12,dps,13,+Z Panel,8,3,3,Rotation,Angular Veolcity around Z Axis +30,RT,EXP4Temperature,12,C,7,NONE,5,0,0,EXP4 Temperature,Not used +31,RT,PSUCurrent,12,mA,cubesatsim_ina219_current,PSU,4,1,3,Current,Power Supply DC Current +32,RT,IHUDiagnosticData,32,-,18,Computer,2,7,0,Diagnostic Info,Diagnostic Data on IHU Performance +33,RT,Experiment1FailureIndication,1,-,17,Experiments,5,1,0,STEM Payload Status,STEM Payload Board Status +34,RT,Experiment2FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +35,RT,Experiment3FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +36,RT,Experiment4FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +37,RT,BATTI2CFailureIndications,1,-,17,Computer,2,3,0,Battery I2C,Battery I2C Bus failure indicator +38,RT,PSU1I2CFailureIndications,1,-,17,Computer,2,4,0,PSU1 I2C,PSU2 I2C Bus failure indicator +39,RT,PSU2I2CFailureIndications,1,-,17,Computer,2,5,0,PSU2 I2C,PSU2 I2C Bus failure indicator +40,RT,NumberofGroundCommandedTLMResets,4,-,1,Computer,2,6,0,Ground Resets,Number of times command stations reset stored telemetry +41,RT,RXAntenna,1,-,16,Radio,1,4,0,RX Antenna,70cm Antenna status +42,RT,TXAntenna,1,-,16,Radio,1,3,0,TX Antenna,2m Antenna status +43,RT,Pad,51,-,0,NONE,0,0,0,NONE,NONE diff --git a/spacecraft/FoxTelem_1.09f/CubeSat_Simulator_DUV_fm.MASTER b/spacecraft/FoxTelem_1.09f/CubeSat_Simulator_DUV_fm.MASTER new file mode 100644 index 00000000..665c75f4 --- /dev/null +++ b/spacecraft/FoxTelem_1.09f/CubeSat_Simulator_DUV_fm.MASTER @@ -0,0 +1,54 @@ +#Fox 1 Telemetry Decoder Properties +#Sat Sept 22 18:12:20 EST 2019 +#File named .dat should be in the logfiles directory and is loaded by FoxTelem +#File named .MASTER should not be edited and is a backup copy in the installation directory +foxId=7 +displayName=CubeSat Simulator DUV +name=CubeSat Simulator DUV +model=0 +IHU_SN=7 +catalogNumber=0 +description=CubeSat Simulator is a functional satellite model that generates real telemetry from solar panels, batteries, and temperature sensors. Use this for DUV FSK telemetry. For more information see http://cubesatsim.org +BATTERY_CURRENT_ZERO=-1.839 +EXP1=0 +EXP2=0 +EXP3=0 +EXP4=0 +numberOfLayouts=4 +layout0.filename=FOX1A_debug.csv +layout0.name=DEBUG +layout1.filename=FOX1A_maxtelemetry.csv +layout1.name=maxtelemetry +layout2.filename=CubeSatSim_rttelemetryFM.csv +layout2.name=rttelemetry +layout3.filename=FOX1A_mintelemetry.csv +layout3.name=mintelemetry +#layout4.filename=FOX1A_radtelemetry.csv +#layout4.name=radtelemetry +#layout5.filename=FOX1A_radtelemetry2.csv +#layout5.name=radtelemetry2 +#layout5.parentLayout=radtelemetry +lookupTable0.filename=FOX1A_rssiFM.tab +numberOfLookupTables=3 +lookupTable0=RSSI +lookupTable1.filename=FOX1A_ihuVBattSN7.tab +lookupTable1=IHU_VBATT +lookupTable2.filename=FOX1A_ihutempSN7.tab +lookupTable2=IHU_TEMP +telemetryDownlinkFreqkHz=434900 +maxFreqBoundkHz=434950 +minFreqBoundkHz=434850 +measurementsFileName=measurements.csv +memsRestValueX=2087 +memsRestValueY=2101 +memsRestValueZ=2045 +passMeasurementsFileName=passmeasurements.csv +numberOfSources=1 +source0.name=ihu.duv +#source1.name=ihu.highspeed +track=true +useIHUVBatt=true +user_mode=0 +user_format=0 +useConversionCoeffs=true +conversionCurvesFileName=cubesatsim_conversion_curves.csv \ No newline at end of file diff --git a/spacecraft/FoxTelem_1.09f/CubeSat_Simulator_PSK_fm.MASTER b/spacecraft/FoxTelem_1.09f/CubeSat_Simulator_PSK_fm.MASTER new file mode 100644 index 00000000..1161df75 --- /dev/null +++ b/spacecraft/FoxTelem_1.09f/CubeSat_Simulator_PSK_fm.MASTER @@ -0,0 +1,72 @@ +#Fox 1 Telemetry Decoder Properties +#Thu Feb 09 21:13:22 EST 2017 +user_mode=4 +foxId=99 +IHU_SN=7 +catalogNumber=0 +model=1 +mpptResistanceError=6.58 +mpptSensorOffThreshold=1600 +name=CubeSat Simulator PSK +displayName=CubeSat Simulator PSK +BATTERY_CURRENT_ZERO=-1.834 +hasImprovedCommandReceiver=true +EXP1=6 +EXP2=1 +EXP3=8 +EXP4=7 +description=CubeSat Simulator is a functional satellite model that generates real telemetry from solar panels, batteries, and temperature sensors. Use this for BPSK telemetry. For more information see http://cubesatsim.org +numberOfFrameLayouts=5 +frameLayout0.filename=FOX1E_Type0_ALL_WOD.frame +frameLayout0.name=All WOD +frameLayout1.filename=FOX1E_Type1_HEALTH.frame +frameLayout1.name=Health +frameLayout2.filename=FOX1E_Type2_MINMAX.frame +frameLayout2.name=MinMax +frameLayout3.filename=FOX1E_Type3_REALTIME_BEACON.frame +frameLayout3.name=Realtime Beacon +frameLayout4.filename=FOX1E_Type4_WOD_BEACON.frame +frameLayout4.name=WOD Beacon +numberOfLayouts=9 +layout0.filename=FOX1A_debug.csv +layout0.name=DEBUG +layout1.filename=FOX1E_maxtelemetry.csv +layout1.name=maxtelemetry +layout2.filename=cubesatsim_psk_rttelemetry.csv +layout2.name=rttelemetry +layout3.filename=FOX1E_mintelemetry.csv +layout3.name=mintelemetry +layout4.filename=FOX1E_radtelemetry.csv +layout4.name=radtelemetry +layout5.filename=FOX1E_radtelemetry2.csv +layout5.name=radtelemetry2 +layout5.parentLayout=radtelemetry +layout6.filename=FOX1E_wodtelemetry.csv +layout6.name=wodtelemetry +layout7.filename=FOX1E_wodradtelemetry.csv +layout7.name=wodradtelemetry +layout8.filename=FOX1E_wodradtelemetry2.csv +layout8.name=wodradtelemetry2 +layout8.parentLayout=wodradtelemetry +numberOfLookupTables=3 +lookupTable0.filename=FOX1A_rssiFM.tab +lookupTable0=RSSI +lookupTable1.filename=FOX1E_ihuVBattSNx.tab +lookupTable1=IHU_VBATT +lookupTable2.filename=FOX1A_ihutempSN7.tab +lookupTable2=IHU_TEMP +maxFreqBoundkHz=434950 +measurementsFileName=measurements.csv +memsRestValueX=2129 +memsRestValueY=2131 +memsRestValueZ=2103 +minFreqBoundkHz=434850 +passMeasurementsFileName=passmeasurements.csv +telemetryDownlinkFreqkHz=434900 +track=false +useIHUVBatt=false +numberOfSources=1 +source0.name=ihu.bpsk +user_format=0 +useConversionCoeffs=true +conversionCurvesFileName=cubesatsim_conversion_curves.csv diff --git a/spacecraft/FoxTelem_1.09f/README.md b/spacecraft/FoxTelem_1.09f/README.md new file mode 100644 index 00000000..58d18791 --- /dev/null +++ b/spacecraft/FoxTelem_1.09f/README.md @@ -0,0 +1 @@ +These files are for FoxTelem version 1.09f in the spacecraft directory diff --git a/spacecraft/FoxTelem_1.09f/cubesatsim_conversion_curves.csv b/spacecraft/FoxTelem_1.09f/cubesatsim_conversion_curves.csv new file mode 100644 index 00000000..3babc59c --- /dev/null +++ b/spacecraft/FoxTelem_1.09f/cubesatsim_conversion_curves.csv @@ -0,0 +1,4 @@ +CurveName,a,bx,cx^2,dx^3,ex^4,fx^5,Description +cubesatsim_ina219_voltage,0,0.01,0,0,0,0,Converts voltages read from the INA219 sensors +cubesatsim_ina219_current,-2048,1,0,0,0,0,Converts positive and negative currents read from the INA219 sensors +cubesatsim_temperature,0,0.1,0,0,0,0,Converts temperature of Pi diff --git a/spacecraft/FoxTelem_1.09f/cubesatsim_psk_rttelemetry.csv b/spacecraft/FoxTelem_1.09f/cubesatsim_psk_rttelemetry.csv new file mode 100644 index 00000000..376ac37d --- /dev/null +++ b/spacecraft/FoxTelem_1.09f/cubesatsim_psk_rttelemetry.csv @@ -0,0 +1,61 @@ +60,TYPE,FIELD,BITS,UNIT,CONVERSION,MODULE,MODULE_NUM,MODULE_LINE,LINE_TYPE,SHORT_NAME,DESCRIPTION +0,realTime,BATT_A_V,12,V,4,NONE,4,1,3,Cell A,Battery pair A voltage (0-2.5V scale) +1,realTime,BATT_B_V,12,V,4,NONE,4,2,3,Cell A + B,Battery pairs A+B voltage (0-3.3V scale) +2,realTime,BATT_V,12,V,cubesatsim_ina219_voltage,Battery,4,1,3,Cell A + B + C,Cell A + B + C,Battery A+B+C voltage (0-5.0V scale) +3,realTime,battAtemp,12,C,8,NONE,4,4,3,Temperature A,Battery pair A temperature +4,realTime,battBtemp,12,C,8,NONE,4,5,3,Temperature B,Battery pair B temperature +5,realTime,battCtemp,12,C,8,NONE,4,6,3,Temperature C,Battery pair C temperature +6,realTime,battCurr,12,mA,cubesatsim_ina219_current,Battery,4,2,4,Current,Total Battery DC current +7,realTime,battCardTemp,12,C,8,NONE,4,8,3,Board Temp,Battery Card Temperature +8,realTime,posXv,12,V,cubesatsim_ina219_voltage,+X Panel,8,1,3,Voltage,+X solar Panel voltage +9,realTime,posYv,12,V,cubesatsim_ina219_voltage,+Y Panel,9,1,3,Voltage,+Y solar Panel voltage +10,realTime,posZv,12,V,cubesatsim_ina219_voltage,+Z Panel,10,1,3,Voltage,+Z solar Panel voltage +11,realTime,negXv,12,V,cubesatsim_ina219_voltage,-X Panel,11,1,3,Voltage,-X solar Panel voltage +12,realTime,negYv,12,V,cubesatsim_ina219_voltage,-Y Panel,12,1,3,Voltage,-Y solar Panel voltage +13,realTime,negZv,12,V,cubesatsim_ina219_voltage,-Z Panel,13,1,3,Voltage,-Z solar Panel voltage +14,realTime,posXi,12,mA,cubesatsim_ina219_current,+X Panel,8,2,4,Current,+X solar Panel current +15,realTime,posYi,12,mA,cubesatsim_ina219_current,+Y Panel,9,2,4,Current,+Y solar Panel current +16,realTime,posZi,12,mA,cubesatsim_ina219_current,+Z Panel,10,2,4,Current,+Z solar Panel current +17,realTime,negXi,12,mA,cubesatsim_ina219_current,-X Panel,11,2,4,Current,-X solar Panel current +18,realTime,negYi,12,mA,cubesatsim_ina219_current,-Y Panel,12,2,4,Current,-Y solar Panel current +19,realTime,negZi,12,mA,cubesatsim_ina219_current,-Z Panel,13,2,4,Current,-Z solar Panel current +20,realTime,PSUVoltage,12,V,cubesatsim_ina219_voltage,PSU,5,2,3,Board Voltage,Power Supply Voltage +21,realTime,spin,12,rpm,12,Computer Software,3,1,3,Spacecraft Spin,Calculated spin rate using solar cells +22,realTime,TxPAi,12,mA,38,Radio,1,2,3,PA Current,Transmit power amplifier current +23,realTime,TxTemp,12,C,37,Radio,1,1,3,TX Temperature,Transmitter card temperature +24,realTime,FwdPower,12,mW,40,Radio,1,4,3,Fwd Power,Receiver card temperature +25,realTime,rssi,12,dBm,14,Radio,1,3,3,RSSI,Received Signal Strength Indication +26,realTime,IHUcpuTemp,12,C,cubesatsim_temperature,Computer Hardware,2,1,3,Temperature,Internal Temperature of IHU +27,realTime,SatelliteXAxisAngularVelocity,12,dps,13,+X Panel,8,3,3,Rotation,Angular Veolcity around X Axis +28,realTime,SatelliteYAxisAngularVelocity,12,dps,13,+Y Panel,9,3,3,Rotation,Angular Veolcity around Y Axis +29,realTime,SatelliteZAxisAngularVelocity,12,dps,13,+Z Panel,10,3,3,Rotation,Angular Veolcity around Z Axis +30,realTime,Exp4Temp,12,C,7,Experiments,6,1,3,EXP4 Temp,Experiment 4 card temperature +31,realTime,PSUCurrent,12,mA,cubesatsim_ina219_current,PSU,5,1,3,Current,Power Supply DC Current +32,realTime,ReflectedPwr,12,mW,41,Radio,1,5,3,Ref Power,Reflected Power from the Transmit Antenna +33,realTime,ICR3V,12,V,43,Command Receiver (ICR),7,1,3,3V,ICR 3V +34,realTime,ICR3VProt,12,V,43,Command Receiver (ICR),7,2,3,3V Prot,ICR 3V Proteted +35,realTime,ICR2dot5V,12,V,43,Command Receiver (ICR),7,3,3,2.5V,ICR 2.5V +36,realTime,ICR2dot5VProt,12,V,43,Command Receiver (ICR),7,4,3,2.5V Prot,ICR 2.5V Protected +37,realTime,rf6,12,-,0,NONE,0,0,0,None,None +38,realTime,rf7,12,-,0,NONE,0,0,0,None,None +39,realTime,MuxTest,12,V,43,Command Receiver (ICR),7,5,3,Sensor Power,Sensor Power Voltage at the ICR +40,realTime,LtVGACtl,12,V,42,Radio,1,6,3,VGA Control,Control Voltage to the Variable Gain Amplifier (VGA) +41,realTime,pad,4,-,34,NONE,0,0,0,None,Unused +42,realTime,IHUdiagData,32,-,18,Computer Software,3,2,0,Diagnostic Info,Diagnostic Data on IHU Performance +43,realTime,expFailure0,1,-,17,Experiments,6,2,0,Vanderbilt Radiation,Vanderbilt University Vulcan Experiment Indicator +44,realTime,expFailure1,1,-,17,Experiments,6,3,0,Exp 1,Experiment 1 Failure Indicator +45,realTime,expFailure2,1,-,17,Experiments,6,4,0,Exp 2,Experiment 2 Failure Indicator +46,realTime,expFailure3,1,-,17,Experiments,6,5,0,Exp 3,Experiment 3 Failure Indicator +47,realTime,I2CfailureBatt,1,-,17,Computer Hardware,2,2,0,Battery I2C,Battery I2C Bus failure indicator +48,realTime,I2CfailurePSU1,1,-,17,Computer Hardware,2,3,0,PSU1 I2C,PSU2 I2C Bus failure indicator +49,realTime,I2CfailurePSU2,1,-,17,Computer Hardware,2,4,0,PSU2 I2C,PSU2 I2C Bus failure indicator +50,realTime,TLMresets,4,-,1,Computer Hardware,2,6,0,Ground Resets,Number of times command stations reset stored telemetry +51,realTime,RxAntDeploy,1,-,16,Radio,1,8,0,RX Antenna,2m Antenna status +52,realTime,TxAntDeploy,2,-,16,Radio,1,7,0,TX Antenna,70cm Antenna status +53,realTime,I2CfailureRF,1,-,17,Computer Hardware,2,5,0,RF I2C,RF I2C Bus failure indicator +54,realTime,pad1,1,-,0,NONE,0,0,0,NONE,Filler +55,realTime,wodSize,8,000s,36,Computer Software,3,3,0,WOD Stored,Number of WOD data payloads kept for each of Science and Housekeeping. In hundreds +56,realTime,swCmds,32,-,35,Command Receiver (ICR),7,6,0,Diagnostic,ICR Diagnostic information +57,realTime,hwCmdCnt,6,-,1,Command Receiver (ICR),7,7,0,HW Command Count,Number of hardware commands since last reset +58,realTime,swCmdCnt,6,-,1,Command Receiver (ICR),7,8,0,SW Command Count,Number of software commands since last reset +59,realTime,pad2,28,-,0,NONE,0,0,0,NONE,Filler diff --git a/spacecraft/FoxTelem_1.09g/CubeSatSim-BPSK_fm.MASTER b/spacecraft/FoxTelem_1.09g/CubeSatSim-BPSK_fm.MASTER new file mode 100644 index 00000000..f93fc229 --- /dev/null +++ b/spacecraft/FoxTelem_1.09g/CubeSatSim-BPSK_fm.MASTER @@ -0,0 +1,72 @@ +#Fox 1 Telemetry Decoder Properties +#Thu Apr 11 13:23:23 EST 2020 +user_mode=4 +foxId=99 +IHU_SN=7 +catalogNumber=0 +model=1 +mpptResistanceError=6.58 +mpptSensorOffThreshold=1600 +name=CubeSatSim +displayName=CubeSatSim-BPSK +BATTERY_CURRENT_ZERO=-1.834 +hasImprovedCommandReceiver=true +EXP1=6 +EXP2=1 +EXP3=8 +EXP4=7 +description=CubeSatSim, the AMSAT CubeSat Simulator, is a functional satellite model that generates real telemetry from solar panels, batteries, and temperature sensors. Use this for BPSK telemetry. For more information see http://cubesatsim.org +numberOfFrameLayouts=5 +frameLayout0.filename=FOX1E_Type0_ALL_WOD.frame +frameLayout0.name=All WOD +frameLayout1.filename=FOX1E_Type1_HEALTH.frame +frameLayout1.name=Health +frameLayout2.filename=FOX1E_Type2_MINMAX.frame +frameLayout2.name=MinMax +frameLayout3.filename=FOX1E_Type3_REALTIME_BEACON.frame +frameLayout3.name=Realtime Beacon +frameLayout4.filename=FOX1E_Type4_WOD_BEACON.frame +frameLayout4.name=WOD Beacon +numberOfLayouts=9 +layout0.filename=FOX1A_debug.csv +layout0.name=DEBUG +layout1.filename=FOX1E_maxtelemetry.csv +layout1.name=maxtelemetry +layout2.filename=cubesatsim_psk_rttelemetry.csv +layout2.name=rttelemetry +layout3.filename=FOX1E_mintelemetry.csv +layout3.name=mintelemetry +layout4.filename=FOX1E_radtelemetry.csv +layout4.name=radtelemetry +layout5.filename=FOX1E_radtelemetry2.csv +layout5.name=radtelemetry2 +layout5.parentLayout=radtelemetry +layout6.filename=FOX1E_wodtelemetry.csv +layout6.name=wodtelemetry +layout7.filename=FOX1E_wodradtelemetry.csv +layout7.name=wodradtelemetry +layout8.filename=FOX1E_wodradtelemetry2.csv +layout8.name=wodradtelemetry2 +layout8.parentLayout=wodradtelemetry +numberOfLookupTables=3 +lookupTable0.filename=FOX1A_rssiFM.tab +lookupTable0=RSSI +lookupTable1.filename=FOX1E_ihuVBattSNx.tab +lookupTable1=IHU_VBATT +lookupTable2.filename=FOX1A_ihutempSN7.tab +lookupTable2=IHU_TEMP +maxFreqBoundkHz=434950 +measurementsFileName=measurements.csv +memsRestValueX=2129 +memsRestValueY=2131 +memsRestValueZ=2103 +minFreqBoundkHz=434850 +passMeasurementsFileName=passmeasurements.csv +telemetryDownlinkFreqkHz=434900 +track=false +useIHUVBatt=false +numberOfSources=1 +source0.name=ihu.bpsk +user_format=0 +useConversionCoeffs=true +conversionCurvesFileName=cubesatsim_conversion_curves.csv diff --git a/spacecraft/FoxTelem_1.09g/CubeSatSim-FSK_fm.MASTER b/spacecraft/FoxTelem_1.09g/CubeSatSim-FSK_fm.MASTER new file mode 100644 index 00000000..aaadf9ce --- /dev/null +++ b/spacecraft/FoxTelem_1.09g/CubeSatSim-FSK_fm.MASTER @@ -0,0 +1,54 @@ +#Fox 1 Telemetry Decoder Properties +#Sat Apr 11 13:20:20 EST 2020 +#File named .dat should be in the logfiles directory and is loaded by FoxTelem +#File named .MASTER should not be edited and is a backup copy in the installation directory +foxId=7 +displayName=CubeSatSim-FSK +name=CubeSatSim +model=0 +IHU_SN=7 +catalogNumber=0 +description=CubeSatSim, the AMSAT CubeSat Simulator, is a functional satellite model that generates real telemetry from solar panels, batteries, and temperature sensors. Use this for DUV FSK telemetry. For more information see http://cubesatsim.org +BATTERY_CURRENT_ZERO=-1.839 +EXP1=0 +EXP2=0 +EXP3=0 +EXP4=0 +numberOfLayouts=4 +layout0.filename=FOX1A_debug.csv +layout0.name=DEBUG +layout1.filename=FOX1A_maxtelemetry.csv +layout1.name=maxtelemetry +layout2.filename=CubeSatSim_rttelemetryFM.csv +layout2.name=rttelemetry +layout3.filename=FOX1A_mintelemetry.csv +layout3.name=mintelemetry +#layout4.filename=FOX1A_radtelemetry.csv +#layout4.name=radtelemetry +#layout5.filename=FOX1A_radtelemetry2.csv +#layout5.name=radtelemetry2 +#layout5.parentLayout=radtelemetry +lookupTable0.filename=FOX1A_rssiFM.tab +numberOfLookupTables=3 +lookupTable0=RSSI +lookupTable1.filename=FOX1A_ihuVBattSN7.tab +lookupTable1=IHU_VBATT +lookupTable2.filename=FOX1A_ihutempSN7.tab +lookupTable2=IHU_TEMP +telemetryDownlinkFreqkHz=434900 +maxFreqBoundkHz=434950 +minFreqBoundkHz=434850 +measurementsFileName=measurements.csv +memsRestValueX=2087 +memsRestValueY=2101 +memsRestValueZ=2045 +passMeasurementsFileName=passmeasurements.csv +numberOfSources=1 +source0.name=ihu.duv +#source1.name=ihu.highspeed +track=true +useIHUVBatt=true +user_mode=0 +user_format=0 +useConversionCoeffs=true +conversionCurvesFileName=cubesatsim_conversion_curves.csv diff --git a/spacecraft/FoxTelem_1.09g/CubeSatSim_rttelemetryFM.csv b/spacecraft/FoxTelem_1.09g/CubeSatSim_rttelemetryFM.csv new file mode 100644 index 00000000..68207d70 --- /dev/null +++ b/spacecraft/FoxTelem_1.09g/CubeSatSim_rttelemetryFM.csv @@ -0,0 +1,45 @@ +44,TYPE,FIELD,BITS,UNIT,CONVERSION,MODULE,MODULE_NUM,MODULE_LINE,LINE_TYPE,SHORT_NAME,DESCRIPTION +0,RT,BATT_A_V,12,V,4,NONE,0,0,3,Cell A,Battery pair A voltage (0-2.5V scale) +1,RT,BATT_B_V,12,V,4,NONE,0,0,3,Cell A + B,Battery pairs A+B voltage (0-3.3V scale) +2,RT,BATT_V,12,V,cubesatsim_ina219_voltage,Battery,3,1,3,Cell A + B + C,Battery A+B+C voltage (0-5.0V scale) +3,RT,BATT_A_T,12,C,8,NONE,0,0,3,Temperature A,Battery pair A temperature +4,RT,BATT_B_T,12,C,8,NONE,0,0,3,Temperature B,Battery pair B temperature +5,RT,BATT_C_T,12,C,8,NONE,0,0,3,Temperature C,Battery pair C temperature +6,RT,TOTAL_BATT_I,12,mA,cubesatsim_ina219_current,Battery,3,2,3,Current,Total Battery DC current +7,RT,BATTBoardTemperature,12,C,8,NONE,0,0,3,Board Temp,Battery Card Temperature +8,RT,PANEL_PLUS_X_V,12,V,cubesatsim_ina219_voltage,+X Panel,6,2,3,Voltage,+X Panel +9,RT,PANEL_MINUS_X_V,12,V,cubesatsim_ina219_voltage,-X Panel,9,2,3,Voltage,-X Panel +10,RT,PANEL_PLUS_Y_V,12,V,cubesatsim_ina219_voltage,+Y Panel,7,2,3,Voltage,+YPanel +11,RT,PANEL_MINUS_Y_V,12,V,cubesatsim_ina219_voltage,-Y Panel,10,2,3,Voltage,-Y Panel +12,RT,PANEL_PLUS_Z_V,12,V,cubesatsim_ina219_voltage,+Z Panel,8,2,3,Voltage,+Z Panel +13,RT,PANEL_MINUS_Z_V,12,V,cubesatsim_ina219_voltage,-Z Panel,11,2,3,Voltage,-Z Panel +14,RT,PANEL_PLUS_X_I,12,mA,cubesatsim_ina219_current,+X Panel,6,1,3,Current,+X Panel +15,RT,PANEL_MINUS_X_I,12,mA,cubesatsim_ina219_current,-X Panel,9,1,3,Current,-X Panel +16,RT,PANEL_PLUS_Y_I,12,mA,cubesatsim_ina219_current,+Y Panel,7,1,3,Current,+Y Panel +17,RT,PANEL_MINUS_Y_I,12,mA,cubesatsim_ina219_current,-Y Panel,10,1,3,Current,-Y Panel +18,RT,PANEL_PLUS_Z_I,12,mA,cubesatsim_ina219_current,+Z Panel,8,1,3,Current,+Z Panel +19,RT,PANEL_MINUS_Z_I,12,mA,cubesatsim_ina219_current,-Z Panel,11,1,3,Current,-Z Panel +20,RT,PSUVoltage,12,V,cubesatsim_ina219_voltage,PSU,4,2,3,Board Voltage,Power Supply Voltage +21,RT,SPIN,12,rpm,12,Computer,2,2,3,Spacecraft Spin,Calculated spin rate using solar cells +22,RT,TXPACurrent,12,mA,10,NONE,1,0,3,PA Current,Transmit power amplifier current +23,RT,TXTemperature,12,C,7,NONE,1,0,3,TX Temperature,Transmitter card temperature +24,RT,RXTemperature,12,C,7,Radio,1,1,3,RX Temperature,Receiver card temperature +25,RT,RSSI,12,dBm,14,Radio,1,2,3,RSSI,Received Signal Strength Indication +26,RT,IHUTemperature,12,C,cubesatsim_temperature,Computer,2,1,3,Temperature,Internal Temperature of IHU +27,RT,SatelliteXAxisAngularVelocity,12,dps,13,+X Panel,6,3,3,Rotation,Angular Veolcity around X Axis +28,RT,SatelliteYAxisAngularVelocity,12,dps,13,+Y Panel,7,3,3,Rotation,Angular Veolcity around Y Axis +29,RT,SatelliteZAxisAngularVelocity,12,dps,13,+Z Panel,8,3,3,Rotation,Angular Veolcity around Z Axis +30,RT,EXP4Temperature,12,C,7,NONE,5,0,0,EXP4 Temperature,Not used +31,RT,PSUCurrent,12,mA,cubesatsim_ina219_current,PSU,4,1,3,Current,Power Supply DC Current +32,RT,IHUDiagnosticData,32,-,18,Computer,2,7,0,Diagnostic Info,Diagnostic Data on IHU Performance +33,RT,Experiment1FailureIndication,1,-,17,Experiments,5,1,0,STEM Payload Status,STEM Payload Board Status +34,RT,Experiment2FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +35,RT,Experiment3FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +36,RT,Experiment4FailureIndication,1,-,17,NONE,5,0,0,Not installed,Not used +37,RT,BATTI2CFailureIndications,1,-,17,Computer,2,3,0,Battery I2C,Battery I2C Bus failure indicator +38,RT,PSU1I2CFailureIndications,1,-,17,Computer,2,4,0,PSU1 I2C,PSU2 I2C Bus failure indicator +39,RT,PSU2I2CFailureIndications,1,-,17,Computer,2,5,0,PSU2 I2C,PSU2 I2C Bus failure indicator +40,RT,NumberofGroundCommandedTLMResets,4,-,1,Computer,2,6,0,Ground Resets,Number of times command stations reset stored telemetry +41,RT,RXAntenna,1,-,16,Radio,1,4,0,RX Antenna,70cm Antenna status +42,RT,TXAntenna,1,-,16,Radio,1,3,0,TX Antenna,2m Antenna status +43,RT,Pad,51,-,0,NONE,0,0,0,NONE,NONE diff --git a/spacecraft/FoxTelem_1.09g/FoxTelem Files.zip b/spacecraft/FoxTelem_1.09g/FoxTelem Files.zip new file mode 100644 index 00000000..6c27f31e Binary files /dev/null and b/spacecraft/FoxTelem_1.09g/FoxTelem Files.zip differ diff --git a/spacecraft/FoxTelem_1.09g/cubesatsim_conversion_curves.csv b/spacecraft/FoxTelem_1.09g/cubesatsim_conversion_curves.csv new file mode 100644 index 00000000..da56db77 --- /dev/null +++ b/spacecraft/FoxTelem_1.09g/cubesatsim_conversion_curves.csv @@ -0,0 +1,4 @@ +CurveName,a,bx,cx^2,dx^3,ex^4,fx^5,Description +cubesatsim_ina219_voltage,0,0.01,0,0,0,0,Converts voltages read from the INA219 sensors +cubesatsim_ina219_current,-2048,1,0,0,0,0,Converts positive and negative currents read from the INA219 sensors +cubesatsim_temperature,0,0.1,0,0,0,0,Converts temperature of Pi diff --git a/spacecraft/FoxTelem_1.09g/cubesatsim_psk_rttelemetry.csv b/spacecraft/FoxTelem_1.09g/cubesatsim_psk_rttelemetry.csv new file mode 100644 index 00000000..7e05371a --- /dev/null +++ b/spacecraft/FoxTelem_1.09g/cubesatsim_psk_rttelemetry.csv @@ -0,0 +1,61 @@ +60,TYPE,FIELD,BITS,UNIT,CONVERSION,MODULE,MODULE_NUM,MODULE_LINE,LINE_TYPE,SHORT_NAME,DESCRIPTION +0,realTime,BATT_A_V,12,V,4,NONE,4,1,3,Cell A,Battery pair A voltage (0-2.5V scale) +1,realTime,BATT_B_V,12,V,4,NONE,4,2,3,Cell A + B,Battery pairs A+B voltage (0-3.3V scale) +2,realTime,BATT_V,12,V,cubesatsim_ina219_voltage,Battery,4,1,3,Cell A + B + C,Battery A+B+C voltage (0-5.0V scale) +3,realTime,battAtemp,12,C,8,NONE,4,4,3,Temperature A,Battery pair A temperature +4,realTime,battBtemp,12,C,8,NONE,4,5,3,Temperature B,Battery pair B temperature +5,realTime,battCtemp,12,C,8,NONE,4,6,3,Temperature C,Battery pair C temperature +6,realTime,battCurr,12,mA,cubesatsim_ina219_current,Battery,4,2,4,Current,Total Battery DC current +7,realTime,battCardTemp,12,C,8,NONE,4,8,3,Board Temp,Battery Card Temperature +8,realTime,posXv,12,V,cubesatsim_ina219_voltage,+X Panel,8,1,3,Voltage,+X solar Panel voltage +9,realTime,posYv,12,V,cubesatsim_ina219_voltage,+Y Panel,9,1,3,Voltage,+Y solar Panel voltage +10,realTime,posZv,12,V,cubesatsim_ina219_voltage,+Z Panel,10,1,3,Voltage,+Z solar Panel voltage +11,realTime,negXv,12,V,cubesatsim_ina219_voltage,-X Panel,11,1,3,Voltage,-X solar Panel voltage +12,realTime,negYv,12,V,cubesatsim_ina219_voltage,-Y Panel,12,1,3,Voltage,-Y solar Panel voltage +13,realTime,negZv,12,V,cubesatsim_ina219_voltage,-Z Panel,13,1,3,Voltage,-Z solar Panel voltage +14,realTime,posXi,12,mA,cubesatsim_ina219_current,+X Panel,8,2,4,Current,+X solar Panel current +15,realTime,posYi,12,mA,cubesatsim_ina219_current,+Y Panel,9,2,4,Current,+Y solar Panel current +16,realTime,posZi,12,mA,cubesatsim_ina219_current,+Z Panel,10,2,4,Current,+Z solar Panel current +17,realTime,negXi,12,mA,cubesatsim_ina219_current,-X Panel,11,2,4,Current,-X solar Panel current +18,realTime,negYi,12,mA,cubesatsim_ina219_current,-Y Panel,12,2,4,Current,-Y solar Panel current +19,realTime,negZi,12,mA,cubesatsim_ina219_current,-Z Panel,13,2,4,Current,-Z solar Panel current +20,realTime,PSUVoltage,12,V,cubesatsim_ina219_voltage,PSU,5,2,3,Board Voltage,Power Supply Voltage +21,realTime,spin,12,rpm,12,Computer Software,3,1,3,Spacecraft Spin,Calculated spin rate using solar cells +22,realTime,TxPAi,12,mA,38,Radio,1,2,3,PA Current,Transmit power amplifier current +23,realTime,TxTemp,12,C,37,Radio,1,1,3,TX Temperature,Transmitter card temperature +24,realTime,FwdPower,12,mW,40,Radio,1,4,3,Fwd Power,Receiver card temperature +25,realTime,rssi,12,dBm,14,Radio,1,3,3,RSSI,Received Signal Strength Indication +26,realTime,IHUcpuTemp,12,C,cubesatsim_temperature,Computer Hardware,2,1,3,Temperature,Internal Temperature of IHU +27,realTime,SatelliteXAxisAngularVelocity,12,dps,13,+X Panel,8,3,3,Rotation,Angular Veolcity around X Axis +28,realTime,SatelliteYAxisAngularVelocity,12,dps,13,+Y Panel,9,3,3,Rotation,Angular Veolcity around Y Axis +29,realTime,SatelliteZAxisAngularVelocity,12,dps,13,+Z Panel,10,3,3,Rotation,Angular Veolcity around Z Axis +30,realTime,Exp4Temp,12,C,7,Experiments,6,1,3,EXP4 Temp,Experiment 4 card temperature +31,realTime,PSUCurrent,12,mA,cubesatsim_ina219_current,PSU,5,1,3,Current,Power Supply DC Current +32,realTime,ReflectedPwr,12,mW,41,Radio,1,5,3,Ref Power,Reflected Power from the Transmit Antenna +33,realTime,ICR3V,12,V,43,Command Receiver (ICR),7,1,3,3V,ICR 3V +34,realTime,ICR3VProt,12,V,43,Command Receiver (ICR),7,2,3,3V Prot,ICR 3V Proteted +35,realTime,ICR2dot5V,12,V,43,Command Receiver (ICR),7,3,3,2.5V,ICR 2.5V +36,realTime,ICR2dot5VProt,12,V,43,Command Receiver (ICR),7,4,3,2.5V Prot,ICR 2.5V Protected +37,realTime,rf6,12,-,0,NONE,0,0,0,None,None +38,realTime,rf7,12,-,0,NONE,0,0,0,None,None +39,realTime,MuxTest,12,V,43,Command Receiver (ICR),7,5,3,Sensor Power,Sensor Power Voltage at the ICR +40,realTime,LtVGACtl,12,V,42,Radio,1,6,3,VGA Control,Control Voltage to the Variable Gain Amplifier (VGA) +41,realTime,pad,4,-,34,NONE,0,0,0,None,Unused +42,realTime,IHUdiagData,32,-,18,Computer Software,3,2,0,Diagnostic Info,Diagnostic Data on IHU Performance +43,realTime,expFailure0,1,-,17,Experiments,6,2,0,Vanderbilt Radiation,Vanderbilt University Vulcan Experiment Indicator +44,realTime,expFailure1,1,-,17,Experiments,6,3,0,Exp 1,Experiment 1 Failure Indicator +45,realTime,expFailure2,1,-,17,Experiments,6,4,0,Exp 2,Experiment 2 Failure Indicator +46,realTime,expFailure3,1,-,17,Experiments,6,5,0,Exp 3,Experiment 3 Failure Indicator +47,realTime,I2CfailureBatt,1,-,17,Computer Hardware,2,2,0,Battery I2C,Battery I2C Bus failure indicator +48,realTime,I2CfailurePSU1,1,-,17,Computer Hardware,2,3,0,PSU1 I2C,PSU2 I2C Bus failure indicator +49,realTime,I2CfailurePSU2,1,-,17,Computer Hardware,2,4,0,PSU2 I2C,PSU2 I2C Bus failure indicator +50,realTime,TLMresets,4,-,1,Computer Hardware,2,6,0,Ground Resets,Number of times command stations reset stored telemetry +51,realTime,RxAntDeploy,1,-,16,Radio,1,8,0,RX Antenna,2m Antenna status +52,realTime,TxAntDeploy,2,-,16,Radio,1,7,0,TX Antenna,70cm Antenna status +53,realTime,I2CfailureRF,1,-,17,Computer Hardware,2,5,0,RF I2C,RF I2C Bus failure indicator +54,realTime,pad1,1,-,0,NONE,0,0,0,NONE,Filler +55,realTime,wodSize,8,000s,36,Computer Software,3,3,0,WOD Stored,Number of WOD data payloads kept for each of Science and Housekeeping. In hundreds +56,realTime,swCmds,32,-,35,Command Receiver (ICR),7,6,0,Diagnostic,ICR Diagnostic information +57,realTime,hwCmdCnt,6,-,1,Command Receiver (ICR),7,7,0,HW Command Count,Number of hardware commands since last reset +58,realTime,swCmdCnt,6,-,1,Command Receiver (ICR),7,8,0,SW Command Count,Number of software commands since last reset +59,realTime,pad2,28,-,0,NONE,0,0,0,NONE,Filler diff --git a/spacecraft/README.md b/spacecraft/README.md new file mode 100644 index 00000000..d59160ce --- /dev/null +++ b/spacecraft/README.md @@ -0,0 +1,9 @@ +These files are for FoxTelem, the AMSAT software by Chris Thompson AC3CZ/G0KLA for decoding and displaying Fox-1 series CubeSat telemetry. + +To use FoxTelem with the CubeSat Simulator, you will need to download the latest version number listed in this directory. + +https://www.g0kla.com/foxtelem/downloads/test/ + +Next, download the .MASTER files in the correct version number directory and put them in the FoxTelem spacecraft folder. + +Run FoxTelem, then go under Spacecraft/Add and select the .MASTER files to add the CubeSat Simulator to FoxTelem. diff --git a/systemd/cubesatsim.service b/systemd/cubesatsim.service index 4dc168ba..3da1a46e 100644 --- a/systemd/cubesatsim.service +++ b/systemd/cubesatsim.service @@ -10,4 +10,4 @@ Restart=always User=root [Install] -WantedBy=multi-user.target +WantedBy=default.target