diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + diff --git a/inc/i2c.h b/inc/i2c.h --- a/inc/i2c.h +++ b/inc/i2c.h @@ -4,6 +4,7 @@ #include "stm32f0xx_hal.h" void i2c_init(void); +void i2c_deinit(void); I2C_HandleTypeDef* i2c_get(void); #endif diff --git a/inc/wspr.h b/inc/wspr.h --- a/inc/wspr.h +++ b/inc/wspr.h @@ -5,7 +5,7 @@ void wspr_init(void); void wspr_sleep(void); void wspr_wakeup(void); -void wspr_transmit(uint8_t* grid_locator); +void wspr_transmit(uint8_t* grid_locator, uint8_t send_alternate); #endif diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -14,7 +14,7 @@ // We have access to the 1PPS pin of the gps... could have trim routine for internal oscillator based on this when we have a fix -// Probabl wake up 1 minute early -- 0.45min possible +/- on wakeup time with 15min sync intervals +// Probable wake up 1 minute early -- 0.45min possible +/- on wakeup time with 15min sync intervals // TODO: Add JT9 message with more grid locator digits + altitude + vbatt + temp @@ -40,7 +40,7 @@ uint32_t statled_ontime = 0; int main(void) { HAL_Init(); - HAL_Delay(2000); // startup delay before infinisleep + HAL_Delay(1000); // startup delay before infinisleep sysclk_init(); rtc_init(); @@ -64,12 +64,13 @@ int main(void) uint8_t fix_ok = 0; uint8_t numsats = 0; + uint8_t packet_type = 0; while (1) { // Every 10 minutes, wake up and try to wspr - if(state == SYSTEM_IDLE && (HAL_GetTick() - last_wspr_tx_time > 60000))// * 10)) + if(state == SYSTEM_IDLE && (HAL_GetTick() - last_wspr_tx_time > 60000 /* * 10 */)) { state = SYSTEM_GPSACQ; } @@ -84,7 +85,7 @@ int main(void) // If odd minute if(gps_getdata()->minute % 2) { - // Wait until even minute, coming soon + // Wait until even minute plus one second, coming soon nextwspr_time = HAL_GetTick() + (60000 - (gps_getdata()->second * 1000)); nextwspr_time_valid = 1; @@ -190,7 +191,9 @@ int main(void) __calc_gridloc(grid_locator, latitude_flt, longitude_flt); - wspr_transmit(grid_locator); + // TODO: Switch between alternate and standard packet + wspr_transmit(grid_locator, packet_type); + //packet_type = !packet_type; // alternate packet type last_wspr_tx_time = HAL_GetTick(); state = SYSTEM_IDLE; } 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();