diff --git a/Makefile b/Makefile
index 7e9dd00c..54601dfc 100644
--- a/Makefile
+++ b/Makefile
@@ -2,11 +2,13 @@ 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
@@ -28,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
@@ -57,7 +60,7 @@ radiocw: cw/cw_main.o
radiocw: afsk/ax25.o
radiocw: afsk/ax5043.o
radiocw: afsk/send_afsk.o
- gcc -std=gnu99 $(DEBUG_BEHAVIOR) -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 -lcurl
radiopiglatin: libax5043.a
radiopiglatin: piglatin/piglatin_main.o
@@ -69,29 +72,30 @@ testax5043tx: transmit/transmit_main.o
testax5043rx: libax5043.a
testax5043rx: receive/receive_main.o
- gcc -std=gnu99 $(DEBUG_BEHAVIOR) -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 -lcurl
testax5043init: libax5043.a
testax5043init: init/init_main.o
- gcc -std=gnu99 $(DEBUG_BEHAVIOR) -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 -lcurl
testax50432freq: libax5043.a
testax50432freq: transmit2freq/transmit2freq_main.o
- gcc -std=gnu99 $(DEBUG_BEHAVIOR) -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 -lcurl
testafsktx: libax5043.a
testafsktx: afsktx/ax25.o
testafsktx: afsktx/ax5043.o
testafsktx: afsktx/main.o
- gcc -std=gnu99 $(DEBUG_BEHAVIOR) -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 -lcurl
radioafsk: libax5043.a
radioafsk: afsk/ax25.o
radioafsk: afsk/ax5043.o
radioafsk: afsk/main.o
-radioafsk: afsk/ina219.h
- gcc -std=gnu99 $(DEBUG_BEHAVIOR) -o radioafsk -pedantic -Wall -Wextra -L./ afsk/ax25.o afsk/ax5043.o afsk/main.o -lwiringPi -lax5043
+ gcc $(DEBUG_BEHAVIOR) -o radioafsk -pedantic -Wall -Wextra -L./ afsk/ax25.o afsk/ax5043.o afsk/main.o -lwiringPi -lax5043 -lcurl
+telem: afsk/telem.o
+ gcc $(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
@@ -232,8 +236,13 @@ 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
+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
diff --git a/afsk/ax25.c b/afsk/ax25.c
index 15b127c2..cc3270c8 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,55 @@ 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);
+
+ /* if we don't provide POSTFIELDSIZE, libcurl will strlen() by
+ itself */
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(post_data));
+
+ /* example.com is redirected, so we tell libcurl to follow redirection */
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+
+ /* Perform the request, res will get the return code */
+ res = curl_easy_perform(curl);
+ /* Check for errors */
+ if(res != CURLE_OK)
+ fprintf(stderr, "ERROR: AX25.C curl_easy_perform() failed: %s\n",
+ curl_easy_strerror(res));
+
+ /* always cleanup */
+ 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.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 f626f01e..bfd86ffa 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
*
@@ -17,9 +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
#include
#include
#include
@@ -31,31 +34,23 @@
#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/Adafruit_INA219.h" // From Adafruit INA219 library for Arduino
+
#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
+#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;
@@ -64,42 +59,127 @@ ax5043_conf_t hax5043;
ax25_conf_t hax25;
static void init_rf();
+int twosToInt(int val, int len);
int get_tlm(int tlm[][5]);
-long int timestamp;
void config_x25();
void trans_x25();
-//long int timestamp;
-int tempSensor;
-
int upper_digit(int number);
int lower_digit(int number);
-int charging = 0;
-uint16_t config = (0x2000 | 0x1800 | 0x0180 | 0x0018 | 0x0007 );
+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;
-int x_fd; // I2C bus 0 address 0x40
-int x_powerMultiplier;
-int x_currentDivider;
-int x_calValue;
-int y_fd; // I2C bus 0 address 0x41
-int z_fd; // I2C bos 0 address 0x44
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) ;
- int blink;
- for (blink = 1; blink < 4 ;blink++)
- {
- digitalWrite (0, HIGH) ; delay (500) ;
- digitalWrite (0, LOW) ; delay (500) ;
+ strcpy(src_addr, argv[1]);
}
- digitalWrite (0, HIGH) ;
+
+ wiringPiSetup ();
+ pinMode (0, OUTPUT);
setSpiChannel(SPI_CHANNEL);
setSpiSpeed(SPI_SPEED);
@@ -108,87 +188,25 @@ int main(int argc, char *argv[]) {
int tlm[7][5];
memset(tlm, 0, sizeof tlm);
- timestamp = time(NULL);
-
- int file_i2c = access("/dev/i2c-3", W_OK | R_OK);
- //char *filenam1e = (char*)"/dev/i2c-3";
- if (file_i2c < 0)
- {
- fprintf(stderr,"ERROR: /dev/ic2-3 bus not present\n");
- tempSensor = -1;
- } else
- {
- tempSensor = wiringPiI2CSetupInterface("/dev/i2c-3", 0x48);
- }
-
- #ifdef DEBUG_LOGGING
- fprintf(stderr,"tempSensor: %d \n",tempSensor);
- #endif
-
- int arduinoI2C = access("/dev/i2c-0", W_OK | R_OK);
- if (arduinoI2C < 0)
- {
- fprintf(stderr,"ERROR: /dev/i2c-0 bus not present\n");
- } else {
- arduinoI2C = wiringPiI2CSetupInterface("/dev/i2c-0", 0x4B);
-
- #ifdef DEBUG_LOGGING
- fprintf(stderr,"arduinoI2C: %d\n", arduinoI2C);
- #endif
-
- 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");
- }
- }
-
-// new INA219 current reading code
-
- x_calValue = 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;
-
- file_i2c = access("/dev/i2c-0", W_OK | R_OK);
- if (file_i2c < 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);
- y_fd = wiringPiI2CSetupInterface("/dev/i2c-0", 0x41);
- z_fd = wiringPiI2CSetupInterface("/dev/i2c-0", 0x44);
-
- #ifdef DEBUG_LOGGING
- fprintf(stderr, "Opening of -X fd %d\n", x_fd);
- fprintf(stderr, "Opening of -Y fd %d\n", y_fd);
- fprintf(stderr, "Opening of -Z fd %d\n", z_fd);
- #endif
- }
+ 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 + 85000; // subtracting rx offset of 90kHz
+ 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_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) src_addr, '1',
+ ax25_init(&hax25, (uint8_t *) dest_addr, '1', (uint8_t *) src_addr, '1',
AX25_PREAMBLE_LEN,
AX25_POSTAMBLE_LEN);
@@ -211,16 +229,11 @@ int main(int argc, char *argv[]) {
char header_str[] = "\x03\xf0hi hi ";
strcpy(str, header_str);
- // printf("%s-1>CQ-1:hi hi ", CALLSIGN);
printf("%s-1>%s-1:hi hi ", (uint8_t *)src_addr, (uint8_t *)dest_addr);
int channel;
for (channel = 1; channel < 7; channel++) {
- #ifdef DEBUG_LOGGING
- printf("%d %d %d %d \n", tlm[channel][1], tlm[channel][2], tlm[channel][3], tlm[channel][4]);
- #endif
-
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]),
@@ -229,33 +242,10 @@ int main(int argc, char *argv[]) {
printf("%s",tlm_str);
strcat(str, tlm_str);
}
-
- if (arduinoI2C > 0) { /* Read Arduino payload */
- for(int reg = 0; reg < 4; reg++) {
- sprintf(tlm_str, " %04x",wiringPiI2CReadReg16(arduinoI2C,reg));
- #ifdef DEBUG_LOGGING
- printf("%s \n",tlm_str);
- #endif
- strcat(str,tlm_str); /* Append payload telemetry */
- printf("%s",tlm_str);
- usleep(100000);
- }
- }
printf("\n");
digitalWrite (0, LOW);
-/*
-char cmdbuffer[1000];
-
- if (charging) {
- FILE* file1 = popen("/home/pi/mopower/mpcmd LED_STAT=1", "r");
- fgets(cmdbuffer, 999, file1);
- pclose(file1);
-
-// printf("LED state: %s\n", cmdbuffer);
- }
-*/
#ifdef DEBUG_LOGGING
fprintf(stderr,"INFO: Transmitting X.25 packet\n");
#endif
@@ -271,13 +261,6 @@ char cmdbuffer[1000];
ax5043_wait_for_transmit();
digitalWrite (0, HIGH);
-/*
- FILE* file2 = popen("/home/pi/mopower/mpcmd LED_STAT=0", "r");
- fgets(cmdbuffer, 999, file2);
- pclose(file2);
-
-// printf("LED state: %s\n", cmdbuffer);
-*/
if (ret) {
fprintf(stderr,
"ERROR: Failed to transmit entire AX.25 frame with error code %d\n",
@@ -327,85 +310,40 @@ int upper_digit(int number) {
}
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, 999, file);
- pclose(file);
- #ifdef DEBUG_LOGGING
- fprintf(stderr,"I2C Sensor data: %s\n", cmdbuffer);
- #endif
-
- 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);
+// 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 ("ina219[%d]=%s\n",i,ina219[i]);
+ printf("Read sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n",
+ count, reading[count].voltage, reading[count].current, reading[count].power);
#endif
- data2 = strtok (NULL, " ");
- i++;
- }
-
-// 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);
- wiringPiI2CWriteReg16(x_fd, INA219_REG_CONFIG, config);
- wiringPiI2CWriteReg16(x_fd, INA219_REG_CALIBRATION, x_calValue);
- 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);
- wiringPiI2CWriteReg16(y_fd, INA219_REG_CONFIG, config);
- wiringPiI2CWriteReg16(y_fd, INA219_REG_CALIBRATION, x_calValue);
- 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);
- wiringPiI2CWriteReg16(z_fd, INA219_REG_CONFIG, config);
- wiringPiI2CWriteReg16(z_fd, INA219_REG_CALIBRATION, x_calValue);
- z_current = wiringPiI2CReadReg16(z_fd, INA219_REG_CURRENT) / x_currentDivider;
- z_power = wiringPiI2CReadReg16(z_fd, INA219_REG_POWER) * x_powerMultiplier;
}
- #ifdef DEBUG_LOGGING
- 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));
- #endif
-
- 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);
- #ifdef DEBUG_LOGGING
- printf("Temp Sensor Read: %x\n", tempValue);
- #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;
}
@@ -414,9 +352,11 @@ int get_tlm(int tlm[][5]) {
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);
}
@@ -437,3 +377,12 @@ int get_tlm(int tlm[][5]) {
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/telem.c b/afsk/telem.c
new file mode 100644
index 00000000..56e9778f
--- /dev/null
+++ b/afsk/telem.c
@@ -0,0 +1,232 @@
+/*
+ * Generates telemetry for CubeSat Simulator
+ *
+ * Copyright Alan B. Johnston
+ *
+ * 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/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 = 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);
+ printf("Sensor %s %x | ", bus, address);
+ //#endif
+ return data;
+}
+
+struct SensorConfig sensorV;
+struct SensorData readingV;
+struct SensorConfig tempSensor;
+
+int main(int argc, char *argv[]) {
+
+ if (argc > 1) {
+ ;
+ }
+
+ wiringPiSetup ();
+
+ 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);
+
+ 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);
+
+ sensorV = config_sensor("/dev/i2c-1", 0x44, 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);
+
+ sensorV = config_sensor("/dev/i2c-0", 0x40, 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);
+
+ sensorV = config_sensor("/dev/i2c-0", 0x41, 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);
+
+ sensorV = config_sensor("/dev/i2c-0", 0x44, 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);
+
+
+ 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);
+
+ sensorV = config_sensor("/dev/i2c-1", 0x4a, 2000);
+ readingV = read_sensor_data(sensorV);
+ printf("Bus | sensor[%d] % 4.2fV % 6.1fmA % 6.1fmW \n",
+ BUS, readingV.voltage, readingV.current, readingV.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);
+}