diff --git a/src/wspr.c b/src/wspr.c --- a/src/wspr.c +++ b/src/wspr.c @@ -4,6 +4,7 @@ #include "gpio.h" #include "wspr.h" #include "i2c.h" +#include "gps.h" #include "config.h" @@ -11,9 +12,13 @@ #define WSPR_TONE_SPACING 146 // ~1.46 Hz #define WSPR_CTC 10672 // CTC value for WSPR +char call_orig[7] = "KD8TDF"; +#define DBM_ORIG 10 + + // Test stuff char call[7] = "KD8TDF"; -char loc[5] = "EN72"; +char loc[5] = "EN82"; uint8_t dbm = 10; uint8_t tx_buffer[255]; @@ -48,13 +53,158 @@ void wspr_wakeup(void) // Bring up TCXO and oscillator IC -void wspr_transmit(uint8_t* grid_locator) +void wspr_transmit(uint8_t* grid_locator, uint8_t send_alternate) { // Copy 4 digit grid locator to local buffer; null terminate for(uint8_t i=0; i<4; i++) loc[i] = grid_locator[i]; loc[4] = '\0'; + // Set power to altitude in m / 150 + uint8_t altscaled = gps_getdata()->altitude / 150; + if(altscaled > 60) + altscaled = 60; + + + // If alternate packet, send 0XFXXEN82XX + if(send_alternate) + { + + + + ///////////////////////////////////////////////// + // Composite altitude and sub-maidenhead locator + ///////////////////////////////////////////////// + uint16_t maiden_ext = (loc[4] - 'A') + ((loc[5] - 'A') * 24); // 0-575 + uint16_t altitude_mod = gps_getdata()->altitude / 20; + + // Ciel at 21,340 meters + if(altitude_mod > 1067) + altitude_mod = 1067; // Don't overflow into maidenhead! + + // Compose composite altitude (lsbs) with maidenhead locator (msbs) + uint32_t subalt = (1068 * maiden_ext) + (gps_getdata()->altitude / 20); + + + + //////////////////////////////////////////// + // Encode extended maidenhead and altitude + //////////////////////////////////////////// + call[0] = '0'; + + // Split into chunks of valmax 36, 26, 26, 26 + + // Mask off following 3 26valmax fields + uint32_t chunk = subalt / 26 / 26 / 26; + + // Encode to callsign + if(chunk < 10) + call[1] = '0' + chunk + else + call[1] = chunk - 10 + 'A'; + + // Subtract off previous portion + subalt -= (chunk * 26 * 26 * 26); + + // Mask off following 2 26bit values + chunk = (subalt / 26 / 26); + + call[3] = 'A' + chunk; + + // Subtract off previous portion + subalt -= (chunk * 26 * 26) + + // Mask off following 1 26bit values + chunk = (subalt / 26); + + call[4] = 'A' + chunk; + + // Subtract off previous portion + subalt -= (chunk * 26); + + // Remainder is the last call char + call[5] = 'A' + subalt; + + + //////////////////////////////////////// + // Composite temp/batt/speed/gps + //////////////////////////////////////// + + // Encode value from -50C to 39C => 0-89. TODO: Bounds! + uint8_t temp_enc = 0 + 50; + + // Encode value from 0-39 with some scalar/offset/etc + uint8_t batt_enc = 0; + + // Encode speed in knots from 0-82 to 0-41 + uint8_t speed_enc = gpsdata()->speed / 2; + if(speed_enc > 41) + speed_enc = 41; + + // Encode GPS status + uint8_t gps_status = 0b00; // MSB is valid fix, lsb is sats > 8 + + uint32_t engdata = gps_status + 2 * (speed_enc + 42 * (batt_enc + 40 * temp_enc)); + + //////////////////////////////////////////// + // Encode temp/batt/speed/gps + //////////////////////////////////////////// + + // Mask off fields + chunk = engdata / 18 / 10 / 10 / 19; + + // Encode to grid locator + grid_locator[0] = 'A' + chunk; + + // Subtract off previous portion + engdata -= (chunk * 18 * 10 * 10 * 19); + + // Mask of fields + chunk = engdata / 10 / 10 / 19; + + // Encode to grid locator + grid_locator[1] = 'A' + chunk; + + // Subtract off previous portion + engdata -= (chunk * 10 * 10 * 19); + + // Mask off fields + chunk = engdata / 10 / 19; + + // Encode + grid_locater[2] = '0' + chunk; + + // Subtract + engdata -= (chunk * 10 * 19); + + // Mask off + chunk = engdata / 19; + + // Encode + grid_locator[3] = chunk; + + // Subtract + engdata -= (chunk * 19); + + // Mask off + chunk = engdata; + + // Encode + uint8_t powers[] = {0, 3, 7, 10, 13, 17, 20, 23, 27, 30, 33, 37, 40, 43, 47, 50, 53, 57, 60} + dbm = powers[chunk]; + } + else + { + call[0] = call_orig[0]; + call[1] = call_orig[1]; + call[2] = call_orig[2]; + call[3] = call_orig[3]; + call[4] = call_orig[4]; + call[5] = call_orig[5]; + call[6] = call_orig[6]; + + dbm = DBM_ORIG; + } // Start timer for WSPR __TIM1_CLK_ENABLE();