diff --git a/PiFmRds b/PiFmRds
deleted file mode 160000
index e4e246e8..00000000
--- a/PiFmRds
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e4e246e8d86203c867227d6c8f8b6ab71def39ae
diff --git a/afsk.wav b/afsk.wav
new file mode 100644
index 00000000..ade8de4d
Binary files /dev/null and b/afsk.wav differ
diff --git a/afsk/ax5043.c.bk b/afsk/ax5043.c.bk
new file mode 100644
index 00000000..f5b31b91
--- /dev/null
+++ b/afsk/ax5043.c.bk
@@ -0,0 +1,1162 @@
+/*
+ * 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/cw.wav b/cw.wav
new file mode 100644
index 00000000..276fe223
Binary files /dev/null and b/cw.wav differ
diff --git a/cw/cw_main.bk b/cw/cw_main.bk
new file mode 100644
index 00000000..28e74bd9
--- /dev/null
+++ b/cw/cw_main.bk
@@ -0,0 +1,495 @@
+// Sends CubeSatSim telemetry encoded as CW (Morse Code) using AO-7 format
+//
+// Copyright (c) 2018 Alan Johnston
+//
+// Portions Copyright (c) 2018 Brandenburg Tech, LLC
+// All right reserved.
+//
+// THIS SOFTWARE IS PROVIDED BY BRANDENBURG TECH, LLC AND CONTRIBUTORS
+// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDENBURT TECH, LLC
+// AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include
+#include
+#include
+#include
+#include
+//#include
+//#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAX_MESSAGE_LENGTH (197)
+#define TRUE 1
+#define FALSE 0
+#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
+#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
+
+long int timestamp = 0;
+extern uint8_t axradio_rxbuffer[];
+void *transmit(void *arg);
+int get_message(uint8_t *buffer, int avail);
+int lower_digit(int number);
+int upper_digit(int number);
+int encode_digit(uint8_t *msg, int number);
+void config_cw();
+int encode_tlm(uint8_t *buffer, int channel, int val1, int val2, int val3, int val4, int avail);
+int encode_header(uint8_t *buffer, int avail);
+int add_dash(uint8_t *msg, int number);
+int add_dot(uint8_t *msg, int number);
+int add_space(uint8_t *msg);
+int get_tlm(int tlm[7][5]);
+int tempSensor, xPlusSensor, yPlusSensor, zPlusSensor, battCurrentSensor;
+extern int config_afsk();
+
+int main(void)
+{
+ uint8_t retVal;
+ int tlm[7][5];
+ int i, j;
+ for (i = 1; i < 7; i++) {
+ for (j = 1; j < 5; j++) {
+ tlm[i][j] = 0;
+ }
+ }
+ tempSensor = wiringPiI2CSetupInterface("/dev/i2c-3", 0x48);
+
+ // Configure SPI bus to AX5043
+ setSpiChannel(SPI_CHANNEL);
+ setSpiSpeed(SPI_SPEED);
+ initializeSpi();
+// printf("1\n");
+
+ // if (send_cw_tlm) {
+// Send one frame of CW Telem
+// Initialize the AX5043
+ retVal = axradio_init();
+ if (retVal == AXRADIO_ERR_NOCHIP) {
+ fprintf(stderr, "ERROR: No AX5043 RF chip found\n");
+ exit(EXIT_FAILURE);
+ }
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to initialize AX5043\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("INFO: Found and initialized AX5043\n");
+
+ retVal = mode_tx();
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to enter TX mode\n");
+ exit(EXIT_FAILURE);
+ }
+ config_cw();
+
+ // allocate space for the buffer
+ static uint8_t packet[MAX_MESSAGE_LENGTH + 1];
+
+ int channel; // AO-7 telemetry format has 6 channels, 4 sub channels in each
+ int msg_length;
+
+ while(1) { // loop infinitely
+ for (channel = 0; channel < 7; channel++) {
+
+ get_tlm(tlm);
+ if (channel == 0) {
+
+// start with telemetry header "hi hi" plus a few chars to help CW decoding software sync
+ msg_length = encode_header(&packet[0], MAX_MESSAGE_LENGTH + 1);
+
+ printf("\nINFO: Sending TLM header\n");
+
+ } else {
+
+ msg_length = encode_tlm(&packet[0], channel,
+ tlm[channel][1], tlm[channel][2], tlm[channel][3], tlm[channel][4],
+ (MAX_MESSAGE_LENGTH + 1));
+
+ printf("\nINFO: Sending TLM channel %d \n", channel);
+ }
+ retVal = transmit_packet(&remoteaddr_tx, packet, (uint16_t)(msg_length)); // send telemetry
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to transmit a packet\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ usleep(200000);
+ }
+}
+// Encodes telemetry header (channel 0) into buffer
+//
+int encode_header(uint8_t *buffer, int avail) {
+
+ int count = 0;
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += add_dash(&buffer[count], 1); // c
+ count += add_dot(&buffer[count], 1);
+ count += add_dash(&buffer[count], 1);
+ count += add_dot(&buffer[count], 1);
+ count += add_space(&buffer[count]);
+
+ count += add_dash(&buffer[count], 2); // q
+ count += add_dot(&buffer[count], 1);
+ count += add_dash(&buffer[count], 1);
+ count += add_space(&buffer[count]);
+
+ count += add_space(&buffer[count]);
+
+ count += add_dot(&buffer[count], 4); // h
+ count += add_space(&buffer[count]);
+
+ count += add_dot(&buffer[count], 2); // i
+ count += add_space(&buffer[count]);
+
+ count += add_space(&buffer[count]);
+
+ count += add_dot(&buffer[count], 4); // h
+ count += add_space(&buffer[count]);
+
+ count += add_dot(&buffer[count], 2); // i
+ count += add_space(&buffer[count]);
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ if (count > avail)
+ printf("ERROR: encode_header count > avail \n");
+
+ return count;
+}
+
+// Encodes one channel of telemetry into buffer
+//
+int encode_tlm(uint8_t *buffer, int channel, int val1, int val2, int val3, int val4, int avail) {
+
+ int count = 0;
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += encode_digit(&buffer[count], channel); // for channel 1, encodes 1aa
+ count += encode_digit(&buffer[count], upper_digit(val1));
+ count += encode_digit(&buffer[count], lower_digit(val1));
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += encode_digit(&buffer[count], channel); // for channel 1, encodes 1bb
+ count += encode_digit(&buffer[count], upper_digit(val2));
+ count += encode_digit(&buffer[count], lower_digit(val2));
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += encode_digit(&buffer[count], channel); // for channel 1, encodes 1cc
+ count += encode_digit(&buffer[count], upper_digit(val3));
+ count += encode_digit(&buffer[count], lower_digit(val3));
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += encode_digit(&buffer[count], channel); // for channel 1, encodes 1dd
+ count += encode_digit(&buffer[count], upper_digit(val4));
+ count += encode_digit(&buffer[count], lower_digit(val4));
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ //printf("DEBUG count: %d avail: %d \n", count, avail);
+ if (count > avail) { // make sure not too long
+ buffer[avail-1] = 0;
+ count = avail-1;
+ printf("DEBUG count > avail!\n");
+ }
+return count;
+}
+// Encodes a single digit of telemetry into buffer
+//
+int encode_digit(uint8_t *buffer, int digit) {
+ int count = 0;
+ switch(digit)
+ {
+ case 0:
+ count += add_dash(&buffer[count], 5); // 0
+ count += add_space(&buffer[count]);
+
+ break;
+ case 1:
+ count += add_dot(&buffer[count], 1); // 1
+ count += add_dash(&buffer[count], 4);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 2:
+ count += add_dot(&buffer[count], 2); // 2
+ count += add_dash(&buffer[count], 3);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 3:
+ count += add_dot(&buffer[count], 3); // 3
+ count += add_dash(&buffer[count], 2);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 4:
+ count += add_dot(&buffer[count], 4); // 4
+ count += add_dash(&buffer[count], 1);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 5:
+ count += add_dot(&buffer[count], 5); // 5
+ count += add_space(&buffer[count]);
+
+ break;
+ case 6:
+ count += add_dash(&buffer[count], 1); // 6
+ count += add_dot(&buffer[count], 4);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 7:
+
+ count += add_dash(&buffer[count], 2); // 7
+ count += add_dot(&buffer[count], 3);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 8:
+ count += add_dash(&buffer[count], 3); // 8
+ count += add_dot(&buffer[count], 2);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 9:
+ count += add_dash(&buffer[count], 4); // 9
+ count += add_dot(&buffer[count], 1);
+ count += add_space(&buffer[count]);
+
+ break;
+ default:
+ printf("ERROR: Not a digit!\n");
+ return 0;
+ }
+ return count;
+}
+// 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
+ printf("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
+ printf("ERROR: Not a digit in upper_digit!\n");
+ return digit;
+}
+// Configure radio to send CW which is ASK
+//
+void config_cw() {
+
+ uint8_t retVal;
+
+// Configure SPI bus to AX5043
+// setSpiChannel(SPI_CHANNEL);
+// setSpiSpeed(SPI_SPEED);
+// initializeSpi();
+ // printf("1\n");
+
+ // Initialize the AX5043
+ retVal = axradio_init();
+// printf("2\n");
+ if (retVal == AXRADIO_ERR_NOCHIP) {
+ fprintf(stderr, "ERROR: No AX5043 RF chip found\n");
+ exit(EXIT_FAILURE);
+ }
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to initialize AX5043\n");
+ exit(EXIT_FAILURE);
+ }
+
+// printf("INFO: Found and initialized AX5043\n");
+
+ retVal = mode_tx();
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to enter TX mode\n");
+ exit(EXIT_FAILURE);
+ }
+
+// printf("Register write to clear framing and crc\n");
+ ax5043WriteReg(0x12,0);
+
+// printf("Register write to disable fec\n");
+ ax5043WriteReg(0x18,0);
+
+// printf("Register write \n");
+ ax5043WriteReg(0x165,0);
+
+ ax5043WriteReg(0x166,0);
+ ax5043WriteReg(0x167,0x50); // 0x25); // 0x50); // 0x08); // 0x20);
+
+ ax5043WriteReg(0x161,0);
+ ax5043WriteReg(0x162,0x20);
+
+// long txRate;
+// txRate = ax5043ReadReg(0x167) + 256 * ax5043ReadReg(0x166) + 65536 * ax5043ReadReg(0x165);
+// printf("Tx Rate %x %x %x \n", ax5043ReadReg(0x165), ax5043ReadReg(0x166), ax5043ReadReg(0x167));
+// long fskDev;
+// fskDev = ax5043ReadReg(0x163) + 256 * ax5043ReadReg(0x162) + 65536 * ax5043ReadReg(0x161);
+
+ ax5043WriteReg(0x37,(uint8_t)((ax5043ReadReg(0x37) + 4))); // Increase FREQA
+
+// printf("Tx Rate: %ld FSK Dev: %ld \n", txRate, fskDev);
+
+ ax5043WriteReg(0x10,0); // ASK
+
+// printf("Modulation: %x \n", (int)ax5043ReadReg(0x10));
+// printf("Frequency A: 0x%x %x %x %x \n",(int)ax5043ReadReg(0x34),(int)ax5043ReadReg(0x35),(int)ax5043ReadReg(0x36),(int)ax5043ReadReg(0x37));
+
+/*
+ int x;
+ for (x = 0; x < 0x20; x++)
+ {
+ printf("Register %x contents: %x\n",x,(int)ax5043ReadReg(x));
+ }
+
+ printf("Register Dump complete");
+*/
+ return;
+}
+// Adds a Morse space to the buffer
+//
+int add_space(uint8_t *msg) {
+ msg[0] = 0x00; // a space is 8 bits
+ return 1;
+}
+// Adds a Morse dash to the buffer
+//
+int add_dash(uint8_t *msg, int number) {
+ int j;
+ int counter = 0;
+
+ for (j=0; j < number; j++) { // a dot is 4 bits, so a dash is 12 bits
+ msg[counter++] = 0xff;
+ msg[counter++] = 0x0f;
+ }
+ return counter;
+}
+// Adds a Morse dot to the buffer
+//
+int add_dot(uint8_t *msg, int number) {
+ int counter = 0;
+ int j;
+ for (j=0; j < number; j++) { // a dot is 4 bits
+ msg[counter++] = 0x0f;
+ }
+ return counter;
+}
+int get_tlm(int tlm[][5]) {
+
+// Reading I2C voltage and current sensors
+
+ char cmdbuffer[1000];
+ FILE* file = popen("sudo python /home/pi/CubeSatSim/python/readcurrent.py 2>&1", "r");
+ fgets(cmdbuffer, 1000, file);
+ pclose(file);
+ printf("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++;
+ }
+// 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); // Current of 5V supply to Pi
+ tlm[1][B] = (int) (99.5 - strtof(ina219[SENSOR_40 + CURRENT], NULL)/10); // +X current [4]
+ tlm[1][D] = (int) (99.5 - strtof(ina219[SENSOR_41 + CURRENT], NULL)/10); // +Y current [7]
+ tlm[1][C] = (int) (99.5 - strtof(ina219[SENSOR_44 + CURRENT], NULL)/10); // +Z current [10] (actually -X current, AO-7 didn't have a Z solar panel?)
+
+ tlm[2][B] = 99;
+ tlm[2][C] = (int)((time(NULL) - timestamp) / 15) % 100;
+ tlm[2][D] = (int)(50.5 + strtof(ina219[SENSOR_45 + CURRENT], NULL)/10.0); // NiMH Battery current
+
+ tlm[3][A] = (int)((strtof(ina219[SENSOR_45 + VOLTAGE], NULL) * 10) - 65.5);
+ tlm[3][B] = (int)(strtof(ina219[SENSOR_4A + VOLTAGE], NULL) * 10.0); // 5V supply to Pi
+
+ 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);
+
+ 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]);
+ }
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/cw/cw_main.c b/cw/cw_main.c
index ebf219a9..926644c5 100644
--- a/cw/cw_main.c
+++ b/cw/cw_main.c
@@ -122,7 +122,7 @@ int main(void)
int channel; // AO-7 telemetry format has 6 channels, 4 sub channels in each
int msg_length;
- while(1) { // loop infinitely
+ //while(1) { // loop infinitely
for (channel = 0; channel < 7; channel++) {
get_tlm(tlm);
@@ -149,7 +149,7 @@ int main(void)
}
usleep(200000);
- }
+ //}
}
// Encodes telemetry header (channel 0) into buffer
//
diff --git a/cw/cw_main.c.bk b/cw/cw_main.c.bk
new file mode 100644
index 00000000..8bfb6392
--- /dev/null
+++ b/cw/cw_main.c.bk
@@ -0,0 +1,498 @@
+// Sends CubeSatSim telemetry encoded as CW (Morse Code) using AO-7 format
+//
+// Copyright (c) 2018 Alan Johnston
+//
+// Portions Copyright (c) 2018 Brandenburg Tech, LLC
+// All right reserved.
+//
+// THIS SOFTWARE IS PROVIDED BY BRANDENBURG TECH, LLC AND CONTRIBUTORS
+// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDENBURT TECH, LLC
+// AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include
+#include
+#include
+#include
+#include
+//#include
+//#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAX_MESSAGE_LENGTH (197)
+#define TRUE 1
+#define FALSE 0
+#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
+#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
+
+long int timestamp = 0;
+extern uint8_t axradio_rxbuffer[];
+void *transmit(void *arg);
+int get_message(uint8_t *buffer, int avail);
+int lower_digit(int number);
+int upper_digit(int number);
+int encode_digit(uint8_t *msg, int number);
+void config_cw();
+int encode_tlm(uint8_t *buffer, int channel, int val1, int val2, int val3, int val4, int avail);
+int encode_header(uint8_t *buffer, int avail);
+int add_dash(uint8_t *msg, int number);
+int add_dot(uint8_t *msg, int number);
+int add_space(uint8_t *msg);
+int get_tlm(int tlm[7][5]);
+int tempSensor, xPlusSensor, yPlusSensor, zPlusSensor, battCurrentSensor;
+extern int config_afsk();
+
+int main(void)
+{
+ uint8_t retVal;
+ int tlm[7][5];
+ int i, j;
+ for (i = 1; i < 7; i++) {
+ for (j = 1; j < 5; j++) {
+ tlm[i][j] = 0;
+ }
+ }
+ tempSensor = wiringPiI2CSetupInterface("/dev/i2c-3", 0x48);
+
+ // Configure SPI bus to AX5043
+ setSpiChannel(SPI_CHANNEL);
+ setSpiSpeed(SPI_SPEED);
+ initializeSpi();
+// printf("1\n");
+
+ // if (send_cw_tlm) {
+// Send one frame of CW Telem
+// Initialize the AX5043
+ retVal = axradio_init();
+ if (retVal == AXRADIO_ERR_NOCHIP) {
+ fprintf(stderr, "ERROR: No AX5043 RF chip found\n");
+ exit(EXIT_FAILURE);
+ }
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to initialize AX5043\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("INFO: Found and initialized AX5043\n");
+
+ retVal = mode_tx();
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to enter TX mode\n");
+ exit(EXIT_FAILURE);
+ }
+ config_cw();
+
+ // allocate space for the buffer
+ static uint8_t packet[MAX_MESSAGE_LENGTH + 1];
+
+ int channel; // AO-7 telemetry format has 6 channels, 4 sub channels in each
+ int msg_length;
+
+ while(1) { // loop infinitely
+ for (channel = 0; channel < 7; channel++) {
+
+ get_tlm(tlm);
+ if (channel == 0) {
+
+// start with telemetry header "hi hi" plus a few chars to help CW decoding software sync
+ msg_length = encode_header(&packet[0], MAX_MESSAGE_LENGTH + 1);
+
+ printf("\nINFO: Sending TLM header\n");
+
+ } else {
+
+ msg_length = encode_tlm(&packet[0], channel,
+ tlm[channel][1], tlm[channel][2], tlm[channel][3], tlm[channel][4],
+ (MAX_MESSAGE_LENGTH + 1));
+
+ printf("\nINFO: Sending TLM channel %d \n", channel);
+ }
+ retVal = transmit_packet(&remoteaddr_tx, packet, (uint16_t)(msg_length)); // send telemetry
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to transmit a packet\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ usleep(200000);
+ }
+}
+// Encodes telemetry header (channel 0) into buffer
+//
+int encode_header(uint8_t *buffer, int avail) {
+
+ int count = 0;
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += add_dash(&buffer[count], 1); // c
+ count += add_dot(&buffer[count], 1);
+ count += add_dash(&buffer[count], 1);
+ count += add_dot(&buffer[count], 1);
+ count += add_space(&buffer[count]);
+
+ count += add_dash(&buffer[count], 2); // q
+ count += add_dot(&buffer[count], 1);
+ count += add_dash(&buffer[count], 1);
+ count += add_space(&buffer[count]);
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += add_dot(&buffer[count], 4); // h
+ count += add_space(&buffer[count]);
+
+ count += add_dot(&buffer[count], 2); // i
+ count += add_space(&buffer[count]);
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += add_dot(&buffer[count], 4); // h
+ count += add_space(&buffer[count]);
+
+ count += add_dot(&buffer[count], 2); // i
+ count += add_space(&buffer[count]);
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ if (count > avail)
+ printf("ERROR: encode_header count > avail \n");
+
+ return count;
+}
+
+// Encodes one channel of telemetry into buffer
+//
+int encode_tlm(uint8_t *buffer, int channel, int val1, int val2, int val3, int val4, int avail) {
+
+ int count = 0;
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += encode_digit(&buffer[count], channel); // for channel 1, encodes 1aa
+ count += encode_digit(&buffer[count], upper_digit(val1));
+ count += encode_digit(&buffer[count], lower_digit(val1));
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += encode_digit(&buffer[count], channel); // for channel 1, encodes 1bb
+ count += encode_digit(&buffer[count], upper_digit(val2));
+ count += encode_digit(&buffer[count], lower_digit(val2));
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += encode_digit(&buffer[count], channel); // for channel 1, encodes 1cc
+ count += encode_digit(&buffer[count], upper_digit(val3));
+ count += encode_digit(&buffer[count], lower_digit(val3));
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ count += encode_digit(&buffer[count], channel); // for channel 1, encodes 1dd
+ count += encode_digit(&buffer[count], upper_digit(val4));
+ count += encode_digit(&buffer[count], lower_digit(val4));
+
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+ count += add_space(&buffer[count]);
+
+ //printf("DEBUG count: %d avail: %d \n", count, avail);
+ if (count > avail) { // make sure not too long
+ buffer[avail-1] = 0;
+ count = avail-1;
+ printf("DEBUG count > avail!\n");
+ }
+return count;
+}
+// Encodes a single digit of telemetry into buffer
+//
+int encode_digit(uint8_t *buffer, int digit) {
+ int count = 0;
+ switch(digit)
+ {
+ case 0:
+ count += add_dash(&buffer[count], 5); // 0
+ count += add_space(&buffer[count]);
+
+ break;
+ case 1:
+ count += add_dot(&buffer[count], 1); // 1
+ count += add_dash(&buffer[count], 4);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 2:
+ count += add_dot(&buffer[count], 2); // 2
+ count += add_dash(&buffer[count], 3);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 3:
+ count += add_dot(&buffer[count], 3); // 3
+ count += add_dash(&buffer[count], 2);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 4:
+ count += add_dot(&buffer[count], 4); // 4
+ count += add_dash(&buffer[count], 1);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 5:
+ count += add_dot(&buffer[count], 5); // 5
+ count += add_space(&buffer[count]);
+
+ break;
+ case 6:
+ count += add_dash(&buffer[count], 1); // 6
+ count += add_dot(&buffer[count], 4);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 7:
+
+ count += add_dash(&buffer[count], 2); // 7
+ count += add_dot(&buffer[count], 3);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 8:
+ count += add_dash(&buffer[count], 3); // 8
+ count += add_dot(&buffer[count], 2);
+ count += add_space(&buffer[count]);
+
+ break;
+ case 9:
+ count += add_dash(&buffer[count], 4); // 9
+ count += add_dot(&buffer[count], 1);
+ count += add_space(&buffer[count]);
+
+ break;
+ default:
+ printf("ERROR: Not a digit!\n");
+ return 0;
+ }
+ return count;
+}
+// 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
+ printf("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
+ printf("ERROR: Not a digit in upper_digit!\n");
+ return digit;
+}
+// Configure radio to send CW which is ASK
+//
+void config_cw() {
+
+ uint8_t retVal;
+
+// Configure SPI bus to AX5043
+// setSpiChannel(SPI_CHANNEL);
+// setSpiSpeed(SPI_SPEED);
+// initializeSpi();
+ // printf("1\n");
+
+ // Initialize the AX5043
+ retVal = axradio_init();
+// printf("2\n");
+ if (retVal == AXRADIO_ERR_NOCHIP) {
+ fprintf(stderr, "ERROR: No AX5043 RF chip found\n");
+ exit(EXIT_FAILURE);
+ }
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to initialize AX5043\n");
+ exit(EXIT_FAILURE);
+ }
+
+// printf("INFO: Found and initialized AX5043\n");
+
+ retVal = mode_tx();
+ if (retVal != AXRADIO_ERR_NOERROR) {
+ fprintf(stderr, "ERROR: Unable to enter TX mode\n");
+ exit(EXIT_FAILURE);
+ }
+
+// printf("Register write to clear framing and crc\n");
+ ax5043WriteReg(0x12,0);
+
+// printf("Register write to disable fec\n");
+ ax5043WriteReg(0x18,0);
+
+// printf("Register write \n");
+ ax5043WriteReg(0x165,0);
+
+ ax5043WriteReg(0x166,0);
+ ax5043WriteReg(0x167,0x50); // 0x25); // 0x50); // 0x08); // 0x20);
+
+ ax5043WriteReg(0x161,0);
+ ax5043WriteReg(0x162,0x20);
+
+// long txRate;
+// txRate = ax5043ReadReg(0x167) + 256 * ax5043ReadReg(0x166) + 65536 * ax5043ReadReg(0x165);
+// printf("Tx Rate %x %x %x \n", ax5043ReadReg(0x165), ax5043ReadReg(0x166), ax5043ReadReg(0x167));
+// long fskDev;
+// fskDev = ax5043ReadReg(0x163) + 256 * ax5043ReadReg(0x162) + 65536 * ax5043ReadReg(0x161);
+
+ ax5043WriteReg(0x37,(uint8_t)((ax5043ReadReg(0x37) + 4))); // Increase FREQA
+
+// printf("Tx Rate: %ld FSK Dev: %ld \n", txRate, fskDev);
+
+ ax5043WriteReg(0x10,0); // ASK
+
+// printf("Modulation: %x \n", (int)ax5043ReadReg(0x10));
+// printf("Frequency A: 0x%x %x %x %x \n",(int)ax5043ReadReg(0x34),(int)ax5043ReadReg(0x35),(int)ax5043ReadReg(0x36),(int)ax5043ReadReg(0x37));
+
+/*
+ int x;
+ for (x = 0; x < 0x20; x++)
+ {
+ printf("Register %x contents: %x\n",x,(int)ax5043ReadReg(x));
+ }
+
+ printf("Register Dump complete");
+*/
+ return;
+}
+// Adds a Morse space to the buffer
+//
+int add_space(uint8_t *msg) {
+ msg[0] = 0x00; // a space is 8 bits
+ return 1;
+}
+// Adds a Morse dash to the buffer
+//
+int add_dash(uint8_t *msg, int number) {
+ int j;
+ int counter = 0;
+
+ for (j=0; j < number; j++) { // a dot is 4 bits, so a dash is 12 bits
+ msg[counter++] = 0xff;
+ msg[counter++] = 0x0f;
+ }
+ return counter;
+}
+// Adds a Morse dot to the buffer
+//
+int add_dot(uint8_t *msg, int number) {
+ int counter = 0;
+ int j;
+ for (j=0; j < number; j++) { // a dot is 4 bits
+ msg[counter++] = 0x0f;
+ }
+ return counter;
+}
+int get_tlm(int tlm[][5]) {
+
+// Reading I2C voltage and current sensors
+
+ char cmdbuffer[1000];
+ FILE* file = popen("sudo python /home/pi/CubeSatSim/python/readcurrent.py 2>&1", "r");
+ fgets(cmdbuffer, 1000, file);
+ pclose(file);
+ printf("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++;
+ }
+// 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); // Current of 5V supply to Pi
+ tlm[1][B] = (int) (99.5 - strtof(ina219[SENSOR_40 + CURRENT], NULL)/10); // +X current [4]
+ tlm[1][D] = (int) (99.5 - strtof(ina219[SENSOR_41 + CURRENT], NULL)/10); // +Y current [7]
+ tlm[1][C] = (int) (99.5 - strtof(ina219[SENSOR_44 + CURRENT], NULL)/10); // +Z current [10] (actually -X current, AO-7 didn't have a Z solar panel?)
+
+ tlm[2][B] = 99;
+ tlm[2][C] = (int)((time(NULL) - timestamp) / 15) % 100;
+ tlm[2][D] = (int)(50.5 + strtof(ina219[SENSOR_45 + CURRENT], NULL)/10.0); // NiMH Battery current
+
+ tlm[3][A] = (int)((strtof(ina219[SENSOR_45 + VOLTAGE], NULL) * 10) - 65.5);
+ tlm[3][B] = (int)(strtof(ina219[SENSOR_4A + VOLTAGE], NULL) * 10.0); // 5V supply to Pi
+
+ 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);
+
+ 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]);
+ }
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/radio.cw.bk b/radio.cw.bk
new file mode 100755
index 00000000..e980f3d5
Binary files /dev/null and b/radio.cw.bk differ
diff --git a/radio.cw.bk2 b/radio.cw.bk2
new file mode 100755
index 00000000..e980f3d5
Binary files /dev/null and b/radio.cw.bk2 differ
diff --git a/radio.cw.once b/radio.cw.once
index efcaf22b..d9aac187 100755
Binary files a/radio.cw.once and b/radio.cw.once differ
diff --git a/radio.cw.once.bk b/radio.cw.once.bk
new file mode 100755
index 00000000..efcaf22b
Binary files /dev/null and b/radio.cw.once.bk differ
diff --git a/radioafsk b/radioafsk
new file mode 100755
index 00000000..5554eda4
Binary files /dev/null and b/radioafsk differ
diff --git a/radiocw b/radiocw
new file mode 100755
index 00000000..d9aac187
Binary files /dev/null and b/radiocw differ
diff --git a/receive/.cproject b/receive/.cproject
deleted file mode 100644
index baaad743..00000000
--- a/receive/.cproject
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/receive/.gitignore b/receive/.gitignore
deleted file mode 100644
index 3df573fe..00000000
--- a/receive/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/Debug/
diff --git a/receive/.project b/receive/.project
deleted file mode 100644
index e68b8c5c..00000000
--- a/receive/.project
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
- receive
-
-
-
-
-
- org.eclipse.cdt.managedbuilder.core.genmakebuilder
- clean,full,incremental,
-
-
-
-
- org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
- full,incremental,
-
-
-
-
-
- org.eclipse.cdt.core.cnature
- org.eclipse.cdt.managedbuilder.core.managedBuildNature
- org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
-
-
diff --git a/receive/.settings/language.settings.xml b/receive/.settings/language.settings.xml
deleted file mode 100644
index 9c8c2c6a..00000000
--- a/receive/.settings/language.settings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/receive/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/receive/.settings/org.eclipse.cdt.managedbuilder.core.prefs
deleted file mode 100644
index 3e369141..00000000
--- a/receive/.settings/org.eclipse.cdt.managedbuilder.core.prefs
+++ /dev/null
@@ -1,11 +0,0 @@
-eclipse.preferences.version=1
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/CPATH/delimiter=;
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/CPATH/operation=remove
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/C_INCLUDE_PATH/delimiter=;
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/C_INCLUDE_PATH/operation=remove
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/append=true
-environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/appendContributed=true
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/LIBRARY_PATH/delimiter=;
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/LIBRARY_PATH/operation=remove
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/append=true
-environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1428445818/appendContributed=true
diff --git a/receive/receive_main.c b/receive/receive_main.c
deleted file mode 100644
index cab15001..00000000
--- a/receive/receive_main.c
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2018 Brandenburg Tech, LLC
-// All right reserved.
-//
-// THIS SOFTWARE IS PROVIDED BY BRANDENBURG TECH, LLC AND CONTRIBUTORS
-// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRANDENBURT TECH, LLC
-// AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Copyright (c) 2007,2008,2009,2010,2011,2012,2013, 2014 AXSEM AG
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1.Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// 2.Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-// 3.Neither the name of AXSEM AG, Duebendorf nor the
-// names of its contributors may be used to endorse or promote products
-// derived from this software without specific prior written permission.
-// 4.All advertising materials mentioning features or use of this software
-// must display the following acknowledgement:
-// This product includes software developed by AXSEM AG and its contributors.
-// 5.The usage of this source code is only granted for operation with AX5043
-// and AX8052F143. Porting to other radio or communication devices is
-// strictly prohibited.
-//
-// THIS SOFTWARE IS PROVIDED BY AXSEM AG AND CONTRIBUTORS ``AS IS'' AND ANY
-// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL AXSEM AG AND CONTRIBUTORS BE LIABLE FOR ANY
-// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-extern uint8_t axradio_rxbuffer[];
-
-int main(void)
-{
- uint8_t retVal;
-
- setSpiChannel(SPI_CHANNEL);
- setSpiSpeed(SPI_SPEED);
- initializeSpi();
-
- retVal = axradio_init();
- if (retVal == AXRADIO_ERR_NOCHIP) {
- fprintf(stderr, "ERROR: No AX5043 RF chip found\n");
- exit(EXIT_FAILURE);
- }
- if (retVal != AXRADIO_ERR_NOERROR) {
- fprintf(stderr, "ERROR: Unable to initialize AX5043\n");
- exit(EXIT_FAILURE);
- }
-
- printf("INFO: Found and initialized AX5043\n");
-
- retVal = mode_rx();
- if (retVal != AXRADIO_ERR_NOERROR) {
- fprintf(stderr, "ERROR: Unable to enter RX mode\n");
- exit(EXIT_FAILURE);
- }
-
- for (;;) {
- retVal = receive_packet();
- if (retVal > 0) {
- uint8_t counter = 0;
- while (retVal-- > 0) {
- if (counter > 0 && counter % 16 == 0) {
- printf("\n");
- }
- printf("%02x ", axradio_rxbuffer[counter++]);
- }
- printf("\n");
-
- }
-
- usleep(1000000);
- }
-
- return 0;
-}
-
diff --git a/systemd/cubesatsim.service b/systemd/cubesatsim.service
index 1f2c17ca..5df4d2b3 100644
--- a/systemd/cubesatsim.service
+++ b/systemd/cubesatsim.service
@@ -4,7 +4,7 @@
[Service]
Type=idle
- ExecStart=/home/pi/CubeSatSim/radiocw > /home/pi/CubeSatSim/log.txt 2>&1
+ ExecStart=/home/pi/CubeSatSim/demo.sh > /home/pi/CubeSatSim/log.txt 2>&1
[Install]
WantedBy=multi-user.target