From 5a5d1c1106106bb050725f53139b767d6f075134 Mon Sep 17 00:00:00 2001 From: kgrewal26 Date: Wed, 5 Jul 2023 15:10:49 -0400 Subject: [PATCH 1/5] working integration with frequency switching --- TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h | 30 +-- .../Core/Inc/Recovery Inc/AprsPacket.h | 43 ++++ .../Core/Inc/Recovery Inc/AprsTransmit.h | 2 +- TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h | 6 +- TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c | 228 +++++------------- .../Core/Src/Recovery Src/AprsPacket.c | 194 +++++++++++++++ TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c | 7 +- TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c | 8 +- TagV3.0_U575VGT/Core/Src/app_threadx.c | 9 +- 9 files changed, 323 insertions(+), 204 deletions(-) create mode 100644 TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsPacket.h create mode 100644 TagV3.0_U575VGT/Core/Src/Recovery Src/AprsPacket.c diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h index c88c12f1..b3ede882 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h @@ -18,39 +18,17 @@ * - AprsTransmit -> handles the transmission of the sine wave * - AprsPacket -> breaks the GPS data into appropriate packets */ - -//Library includes #include "tx_api.h" -#define APRS_FLAG 0x7e -#define APRS_CONTROL_FIELD 0x03 -#define APRS_PROTOCOL_ID 0xF0 - -#define APRS_SOURCE_CALLSIGN "J75Y" -#define APRS_SOURCE_SSID 1 - -#define APRS_SYMBOL "/C" -#define APRS_DESTINATION_CALLSIGN "APRS" -#define APRS_DESTINATION_SSID 0 +#define APRS_PACKET_MAX_LENGTH 255 -#define APRS_DIGI_PATH "WIDE2" -#define APRS_DIGI_SSID 2 +#define APRS_PACKET_LENGTH 224 -#define APRS_COMMENT "Build Demonstration" +#define GPS_SLEEP_LENGTH 200000 -#define APRS_CALLSIGN_LENGTH 6 - -#define APRS_DT_POS_CHARACTER '!' -#define APRS_SYM_TABLE_CHAR '1' -#define APRS_SYM_CODE_CHAR 's' - -#define APRS_LATITUDE_LENGTH 9 -#define APRS_LONGITUDE_LENGTH 10 +#define APRS_BASE_SLEEP_LENGTH 1200000 //Main thread entry void aprs_thread_entry(ULONG aprs_thread_input); -//generates an aprs packet given the latitude and longitude -void aprs_generate_packet(float lat, float lon); - #endif /* INC_RECOVERY_INC_APRS_H_ */ diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsPacket.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsPacket.h new file mode 100644 index 00000000..84bad439 --- /dev/null +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsPacket.h @@ -0,0 +1,43 @@ +/* + * AprsPacket.h + * + * Created on: Jul 5, 2023 + * Author: Kaveet + */ + +#ifndef INC_RECOVERY_INC_APRSPACKET_H_ +#define INC_RECOVERY_INC_APRSPACKET_H_ + +//Library includes +#include "tx_api.h" +#include + +#define APRS_FLAG 0x7e +#define APRS_CONTROL_FIELD 0x03 +#define APRS_PROTOCOL_ID 0xF0 + +#define APRS_SOURCE_CALLSIGN "J75Y" +#define APRS_SOURCE_SSID 1 + +#define APRS_SYMBOL "/C" +#define APRS_DESTINATION_CALLSIGN "APRS" +#define APRS_DESTINATION_SSID 0 + +#define APRS_DIGI_PATH "WIDE2" +#define APRS_DIGI_SSID 2 + +#define APRS_COMMENT "Build Demonstration" + +#define APRS_CALLSIGN_LENGTH 6 + +#define APRS_DT_POS_CHARACTER '!' +#define APRS_SYM_TABLE_CHAR '1' +#define APRS_SYM_CODE_CHAR 's' + +#define APRS_LATITUDE_LENGTH 9 +#define APRS_LONGITUDE_LENGTH 10 + +//generates an aprs packet given the latitude and longitude +void aprs_generate_packet(uint8_t * buffer, float lat, float lon); + +#endif /* INC_RECOVERY_INC_APRSPACKET_H_ */ diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h index ba69ed62..34d899be 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h @@ -32,7 +32,7 @@ //Defines //The time to transmit each bit for -//Each ThreadX tick is 100us -> 9 ticks makes it 900us. Based off the PICO code for the old recovery boards, where the bit time is 832us. +//Each ThreadX tick is 50us -> 17 ticks makes it 850us. Based off the PICO code for the old recovery boards, where the bit time is 832us. #define APRS_TRANSMIT_BIT_TIME 17 //The hardware timer periods for 1200Hz and 2400Hz signals diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h index be26728d..15919de7 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h @@ -18,6 +18,8 @@ //Defines #define TX_FREQ "144.3900" #define RX_FREQ "144.3900" +#define DOMINICA_TX_FREQ "145.0500" +#define DOMINICA_RX_FREQ "145.0500" #define VHF_VOLUME_LEVEL 4 //Lengths of messages used to configure the VHF module @@ -48,7 +50,7 @@ -huart - UART handler to talk to the module -isHigh: whether or not to use high power (1W) or low power (0.5W). Passing true means high power. */ -HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh); +HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh, char * txFreq, char * rxFreq); /*Configure the VHF module over UART Parameters: @@ -58,7 +60,7 @@ HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh); -lpf: Apply a low-pass-filter on the signals. -hps: Apply a high-pass-filter on the signals. */ -HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, bool lpf, bool hpf); +HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, bool lpf, bool hpf, char * txFreq, char * rxFreq); //Enables or disbles the push-to-talk pin. Setting true lets us talk to the module (i.e., transmit signals). void set_ptt(bool isTx); diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c index 53177d93..54b934b8 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c @@ -6,209 +6,105 @@ */ #include "Recovery Inc/Aprs.h" +#include "Recovery Inc/VHF.h" #include "Recovery Inc/GPS.h" +#include "Recovery Inc/AprsPacket.h" +#include "Recovery Inc/AprsTransmit.h" #include "main.h" -#include -#include -#include -#include -//Extern variables for HAL handlers +//Extern variables for HAL UART handlers extern UART_HandleTypeDef huart4; extern UART_HandleTypeDef huart3; -static void append_flag(uint8_t * buffer, uint8_t numFlags); -static void append_callsign(uint8_t * buffer, char * callsign, uint8_t ssid); -static void append_gps_data(uint8_t * buffer, float lat, float lon); -static void append_other_data(uint8_t * buffer, uint16_t course, uint16_t speed, char * comment); -static void append_frame_check(uint8_t * buffer, uint8_t buffer_length); +static bool toggleFreq(bool is_gps_dominica, bool is_currently_dominica); void aprs_thread_entry(ULONG aprs_thread_input){ + //buffer for packet data + uint8_t packetBuffer[APRS_PACKET_MAX_LENGTH] = {0}; + //Create the GPS handler and configure it GPS_HandleTypeDef gps; initialize_gps(&huart3, &gps); //Initialize VHF module for transmission. Turn transmission off so we don't hog the frequency - HAL_StatusTypeDef vhf_init_ret = initialize_vhf(huart4, false); + initialize_vhf(huart4, false, TX_FREQ, RX_FREQ); set_ptt(false); - while(1){ - - } -} - -void aprs_generate_packet(float lat, float lon){ - - uint8_t buffer[255] = {0}; - append_flag(buffer, 150); + //We arent in dominica by default + bool isInDominica = false; - append_callsign(&buffer[150], APRS_DESTINATION_CALLSIGN, APRS_DESTINATION_SSID); - - append_callsign(&buffer[157], APRS_SOURCE_CALLSIGN, APRS_SOURCE_SSID); - - //We can also treat the digipeter as a callsign since it has the same format - append_callsign(&buffer[164], APRS_DIGI_PATH, APRS_DIGI_SSID); - buffer[170] += 1; + //Main task loop + while(1){ - //Add the control ID and protocol ID - buffer[171] = APRS_CONTROL_FIELD; - buffer[172] = APRS_PROTOCOL_ID; + //GPS data struct + GPS_Data gps_data; - //Attach the payload (including other control characters) - //TODO: Replace with real GPS data. - append_gps_data(&buffer[173], 42.3636, -71.1259); + //Attempt to get a GPS lock + bool isLocked = get_gps_lock(&gps, &gps_data); - //Attach other information (course, speed and the comment) - append_other_data(&buffer[193], 360, 0, APRS_COMMENT); + //The time we will eventually put this task to sleep for. We assign this assuming the GPS lock has failed (only sleep for a shorter, fixed period of time). + //If we did get a GPS lock, the sleepPeriod will correct itself by the end of the task (be appropriately assigned after APRS transmission) + uint32_t sleepPeriod = GPS_SLEEP_LENGTH; - append_frame_check(buffer, 219); + //If we've locked onto a position, we can start creating an APRS packet. + if (isLocked){ - append_flag(&buffer[221], 3); + aprs_generate_packet(packetBuffer, gps_data.latitude, gps_data.longitude); - HAL_Delay(100); -} + //We first initialized the VHF module with our default frequencies. If we are in Dominica, re-initialize the VHF module to use the dominica frequencies. + // + //The function also handles switching back to the default frequency if we leave dominica + isInDominica = toggleFreq(gps_data.is_dominica, isInDominica); -//Appends the flag character (0x7E) to the buffer 'numFlags' times. -static void append_flag(uint8_t * buffer, uint8_t numFlags){ - - //Add numFlags flag characters to the buffer - for (uint8_t index = 0; index < numFlags; index++){ - buffer[index] = APRS_FLAG; - } -} + //Start transmission + set_ptt(true); -//Appends a callsign to the buffer with its SSID. -static void append_callsign(uint8_t * buffer, char * callsign, uint8_t ssid){ + //Now, transmit the signal through the VHF module. Transmit a few times just for safety. + for (uint8_t transmits = 0; transmits < 3; transmits++){ + aprs_transmit_send_data(packetBuffer, APRS_PACKET_LENGTH); + } - //Determine the length of the callsign - uint8_t length = strlen(callsign); + //end transmission + set_ptt(false); - //Append the callsign to the buffer. Note that ASCII characters must be left shifted by 1 bit as per APRS101 standard - for (uint8_t index = 0; index < length; index++){ - buffer[index] = (callsign[index] << 1); - } - - //The callsign field must be atleast 6 characters long, so fill any missing spots with blanks - if (length < APRS_CALLSIGN_LENGTH){ - for (uint8_t index = length; index < APRS_CALLSIGN_LENGTH; index++){ - //We still need to shift left by 1 bit - buffer[index] = (' ' << 1); + //Set the sleep period for a successful APRS transmission + sleepPeriod = APRS_BASE_SLEEP_LENGTH; } - } - - //Now, we've filled the first 6 bytes with the callsign (index 0-5), so the SSID must be in the 6th index. - //We can find its ASCII character by adding the integer value to the ascii value of '0'. Still need to shift left by 1 bit. - buffer[APRS_CALLSIGN_LENGTH] = (ssid + '0') << 1; -} - -//Appends the GPS data (latitude and longitude) to the buffer -static void append_gps_data(uint8_t * buffer, float lat, float lon){ - - //indicate start of real-time transmission - buffer[0] = APRS_DT_POS_CHARACTER; - //First, create the string containing the latitude and longitude data, then save it into our buffer - bool isNorth = true; - - //If we have a negative value, then the location is in the southern hemisphere. - //Recognize this and then just use the magnitude of the latitude for future calculations. - if (lat < 0){ - isNorth = false; - isNorth *= -1; + //Go to sleep now + tx_thread_sleep(sleepPeriod); } - - //The coordinates we get from the GPS are in degrees and fractional degrees - //We need to extract the whole degrees from this, then the whole minutes and finally the fractional minutes - - //The degrees are just the rounded-down integer - uint8_t latDegWhole = (uint8_t) lat; - - //Find the remainder (fractional degrees) and multiply it by 60 to get the minutes (fractional and whole) - float latMinutes = (lat - latDegWhole) * 60; - - //Whole number minutes is just the fractional component. - uint8_t latMinutesWhole = (uint8_t) latMinutes; - - //Find the remainder (fractional component) and save it to two decimal points (multiply by 100 and cast to int) - uint8_t latMinutesFrac = (latMinutes - latMinutesWhole) * 100; - - //Find our direction indicator (N for North of S for south) - char latDirection = (isNorth) ? 'N' : 'S'; - - //Create our string. We use the format ddmm.hh(N/S), where "d" is degrees, "m" is minutes and "h" is fractional minutes. - //Store this in our buffer. - snprintf(&buffer[1], APRS_LATITUDE_LENGTH, "%02d%02d.%02d%c", latDegWhole, latMinutesWhole, latMinutesFrac, latDirection); - - - //Right now we have the null-terminating character in the buffer "\0". Replace this with our latitude and longitude seperating symbol "1". - buffer[APRS_LATITUDE_LENGTH] = APRS_SYM_TABLE_CHAR; - - //Now, repeat the process for longitude. - bool isEast = true; - - //If its less than 0, remember it as West, and then take the magnitude - if (lon < 0){ - isEast = false; - lon *= -1; - } - - //Find whole number degrees - uint8_t lonDegWhole = (uint8_t) lon; - - //Find remainder (fractional degrees), convert to minutes - float lonMinutes = (lon - lonDegWhole) * 60; - - //Find whole number and fractional minutes. Take two decimal places for the fractional minutes, just like before - uint8_t lonMinutesWhole = (uint8_t) lonMinutes; - uint8_t lonMinutesFractional = (lonMinutes - lonMinutesWhole) * 100; - - //Find direction character - char lonDirection = (isEast) ? 'E' : 'W'; - - //Store this in the buffer, in the format dddmm.hh(E/W) - snprintf(&buffer[APRS_LATITUDE_LENGTH + 1], APRS_LONGITUDE_LENGTH, "%03d%02d.%02d%c", lonDegWhole, lonMinutesWhole, lonMinutesFractional, lonDirection); - - //Appending payload character indicating the APRS symbol (using boat symbol). Replace the null-terminating character with it. - buffer[APRS_LATITUDE_LENGTH + APRS_LONGITUDE_LENGTH] = APRS_SYM_CODE_CHAR; } -//Appends other extra data (course, speed and the comment) -static void append_other_data(uint8_t * buffer, uint16_t course, uint16_t speed, char * comment){ - - //Append the course and speed of the tag (course is the heading 0->360 degrees - uint8_t length = 8 + strlen(comment); - snprintf(buffer, length, "%03d/%03d%s", course, speed, comment); -} - -//Calculates and appends the CRC frame checker. Follows the CRC-16 CCITT standard. -static void append_frame_check(uint8_t * buffer, uint8_t buffer_length){ - - uint16_t crc = 0xFFFF; - - //Loop through each *bit* in the buffer. Only start after the starting flags. - for (uint8_t index = 150; index < buffer_length; index++){ - - uint8_t byte = buffer[index]; - - for (uint8_t bit_index = 0; bit_index < 8; bit_index++){ +/*Reconfigures the VHF module to change the transmission frequency based on where the GPS is. + * + * is_gps_dominica: whether or not the current gps data is in dominica + * is_currently_dominica: whether or not our VHF module is configured to the dominica frequency + * + * Returns: the current state of our configuration (whether or not VHF is configured for dominica + */ +static bool toggleFreq(bool is_gps_dominica, bool is_currently_dominica){ - bool bit = (byte >> bit_index) & 0x01; + //If the GPS is in dominica, but we are not configured for it, switch to dominica + if (is_gps_dominica && !is_currently_dominica){ - //Bit magic for the CRC - unsigned short xorIn; - xorIn = crc ^ bit; + //Re-initialize for dominica frequencies + initialize_vhf(huart4, false, DOMINICA_TX_FREQ, DOMINICA_RX_FREQ); - crc >>= 1; + //Now configured for dominica, return to indicate that + return true; + } + //elseif, we are not in dominica, but we are configured for dominica. Switch back to the regular frequencies + else if (!is_gps_dominica && is_currently_dominica){ - if (xorIn & 0x01) crc ^= 0x8408; + //Re-initialize for default frequencies + initialize_vhf(huart4, false, TX_FREQ, RX_FREQ); - } + //No longer on dominica freq, return to indicate that + return false; } - uint8_t crcLo = (crc & 0xFF) ^ 0xFF; - uint8_t crcHi = (crc >> 8) ^ 0xFF; - - buffer[buffer_length] = crcLo; - buffer[buffer_length + 1] = crcHi; + //else: do nothing + return is_currently_dominica; } diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsPacket.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsPacket.c new file mode 100644 index 00000000..ecf8c932 --- /dev/null +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsPacket.c @@ -0,0 +1,194 @@ +/* + * AprsPacket.c + * + * Created on: Jul 5, 2023 + * Author: Kaveet + */ + +#include "Recovery Inc/AprsPacket.h" +#include "main.h" +#include +#include +#include +#include + +static void append_flag(uint8_t * buffer, uint8_t numFlags); +static void append_callsign(uint8_t * buffer, char * callsign, uint8_t ssid); +static void append_gps_data(uint8_t * buffer, float lat, float lon); +static void append_other_data(uint8_t * buffer, uint16_t course, uint16_t speed, char * comment); +static void append_frame_check(uint8_t * buffer, uint8_t buffer_length); + +void aprs_generate_packet(uint8_t * buffer, float lat, float lon){ + + append_flag(buffer, 150); + + append_callsign(&buffer[150], APRS_DESTINATION_CALLSIGN, APRS_DESTINATION_SSID); + + append_callsign(&buffer[157], APRS_SOURCE_CALLSIGN, APRS_SOURCE_SSID); + + //We can also treat the digipeter as a callsign since it has the same format + append_callsign(&buffer[164], APRS_DIGI_PATH, APRS_DIGI_SSID); + buffer[170] += 1; + + //Add the control ID and protocol ID + buffer[171] = APRS_CONTROL_FIELD; + buffer[172] = APRS_PROTOCOL_ID; + + //Attach the payload (including other control characters) + //TODO: Replace with real GPS data. + append_gps_data(&buffer[173], 42.3636, -71.1259); + + //Attach other information (course, speed and the comment) + append_other_data(&buffer[193], 360, 0, APRS_COMMENT); + + append_frame_check(buffer, 219); + + append_flag(&buffer[221], 3); + + HAL_Delay(100); +} + +//Appends the flag character (0x7E) to the buffer 'numFlags' times. +static void append_flag(uint8_t * buffer, uint8_t numFlags){ + + //Add numFlags flag characters to the buffer + for (uint8_t index = 0; index < numFlags; index++){ + buffer[index] = APRS_FLAG; + } +} + +//Appends a callsign to the buffer with its SSID. +static void append_callsign(uint8_t * buffer, char * callsign, uint8_t ssid){ + + //Determine the length of the callsign + uint8_t length = strlen(callsign); + + //Append the callsign to the buffer. Note that ASCII characters must be left shifted by 1 bit as per APRS101 standard + for (uint8_t index = 0; index < length; index++){ + buffer[index] = (callsign[index] << 1); + } + + //The callsign field must be atleast 6 characters long, so fill any missing spots with blanks + if (length < APRS_CALLSIGN_LENGTH){ + for (uint8_t index = length; index < APRS_CALLSIGN_LENGTH; index++){ + //We still need to shift left by 1 bit + buffer[index] = (' ' << 1); + } + } + + //Now, we've filled the first 6 bytes with the callsign (index 0-5), so the SSID must be in the 6th index. + //We can find its ASCII character by adding the integer value to the ascii value of '0'. Still need to shift left by 1 bit. + buffer[APRS_CALLSIGN_LENGTH] = (ssid + '0') << 1; +} + +//Appends the GPS data (latitude and longitude) to the buffer +static void append_gps_data(uint8_t * buffer, float lat, float lon){ + + //indicate start of real-time transmission + buffer[0] = APRS_DT_POS_CHARACTER; + + //First, create the string containing the latitude and longitude data, then save it into our buffer + bool isNorth = true; + + //If we have a negative value, then the location is in the southern hemisphere. + //Recognize this and then just use the magnitude of the latitude for future calculations. + if (lat < 0){ + isNorth = false; + isNorth *= -1; + } + + //The coordinates we get from the GPS are in degrees and fractional degrees + //We need to extract the whole degrees from this, then the whole minutes and finally the fractional minutes + + //The degrees are just the rounded-down integer + uint8_t latDegWhole = (uint8_t) lat; + + //Find the remainder (fractional degrees) and multiply it by 60 to get the minutes (fractional and whole) + float latMinutes = (lat - latDegWhole) * 60; + + //Whole number minutes is just the fractional component. + uint8_t latMinutesWhole = (uint8_t) latMinutes; + + //Find the remainder (fractional component) and save it to two decimal points (multiply by 100 and cast to int) + uint8_t latMinutesFrac = (latMinutes - latMinutesWhole) * 100; + + //Find our direction indicator (N for North of S for south) + char latDirection = (isNorth) ? 'N' : 'S'; + + //Create our string. We use the format ddmm.hh(N/S), where "d" is degrees, "m" is minutes and "h" is fractional minutes. + //Store this in our buffer. + snprintf(&buffer[1], APRS_LATITUDE_LENGTH, "%02d%02d.%02d%c", latDegWhole, latMinutesWhole, latMinutesFrac, latDirection); + + + //Right now we have the null-terminating character in the buffer "\0". Replace this with our latitude and longitude seperating symbol "1". + buffer[APRS_LATITUDE_LENGTH] = APRS_SYM_TABLE_CHAR; + + //Now, repeat the process for longitude. + bool isEast = true; + + //If its less than 0, remember it as West, and then take the magnitude + if (lon < 0){ + isEast = false; + lon *= -1; + } + + //Find whole number degrees + uint8_t lonDegWhole = (uint8_t) lon; + + //Find remainder (fractional degrees), convert to minutes + float lonMinutes = (lon - lonDegWhole) * 60; + + //Find whole number and fractional minutes. Take two decimal places for the fractional minutes, just like before + uint8_t lonMinutesWhole = (uint8_t) lonMinutes; + uint8_t lonMinutesFractional = (lonMinutes - lonMinutesWhole) * 100; + + //Find direction character + char lonDirection = (isEast) ? 'E' : 'W'; + + //Store this in the buffer, in the format dddmm.hh(E/W) + snprintf(&buffer[APRS_LATITUDE_LENGTH + 1], APRS_LONGITUDE_LENGTH, "%03d%02d.%02d%c", lonDegWhole, lonMinutesWhole, lonMinutesFractional, lonDirection); + + //Appending payload character indicating the APRS symbol (using boat symbol). Replace the null-terminating character with it. + buffer[APRS_LATITUDE_LENGTH + APRS_LONGITUDE_LENGTH] = APRS_SYM_CODE_CHAR; +} + +//Appends other extra data (course, speed and the comment) +static void append_other_data(uint8_t * buffer, uint16_t course, uint16_t speed, char * comment){ + + //Append the course and speed of the tag (course is the heading 0->360 degrees + uint8_t length = 8 + strlen(comment); + snprintf(buffer, length, "%03d/%03d%s", course, speed, comment); +} + +//Calculates and appends the CRC frame checker. Follows the CRC-16 CCITT standard. +static void append_frame_check(uint8_t * buffer, uint8_t buffer_length){ + + uint16_t crc = 0xFFFF; + + //Loop through each *bit* in the buffer. Only start after the starting flags. + for (uint8_t index = 150; index < buffer_length; index++){ + + uint8_t byte = buffer[index]; + + for (uint8_t bit_index = 0; bit_index < 8; bit_index++){ + + bool bit = (byte >> bit_index) & 0x01; + + //Bit magic for the CRC + unsigned short xorIn; + xorIn = crc ^ bit; + + crc >>= 1; + + if (xorIn & 0x01) crc ^= 0x8408; + + } + } + + uint8_t crcLo = (crc & 0xFF) ^ 0xFF; + uint8_t crcHi = (crc >> 8) ^ 0xFF; + + buffer[buffer_length] = crcLo; + buffer[buffer_length + 1] = crcHi; +} + diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c index b72745e6..c05605fa 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c @@ -179,6 +179,11 @@ bool get_gps_lock(GPS_HandleTypeDef* gps, GPS_Data* gps_data){ gps->is_pos_locked = false; + //ensure all valid data flags are false + for (GPS_MsgTypes msg_type = GPS_SIM; msg_type < GPS_NUM_MSG_TYPES; msg_type++){ + gps->data[msg_type].is_valid_data = false; + } + //time trackers for any possible timeouts uint32_t startTime = HAL_GetTick(); uint32_t currentTime = startTime; @@ -208,5 +213,5 @@ bool get_gps_lock(GPS_HandleTypeDef* gps, GPS_Data* gps_data){ //TODO: implement properly bool is_in_dominica(float latitude, float longitude){ - return true; + return false; } diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c index a9f8017c..8d65919b 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c @@ -9,7 +9,7 @@ #include #include -HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh){ +HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh, char * txFreq, char * rxFreq){ //Set the modes of the GPIO pins attached to the vhf module. //Leave PTT floating, set appropriate power level and wake chip @@ -19,10 +19,10 @@ HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh){ wake_vhf(); HAL_Delay(1000); - return configure_dra818v(huart, false, false, false); + return configure_dra818v(huart, false, false, false, txFreq, rxFreq); } -HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, bool lpf, bool hpf){ +HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, bool lpf, bool hpf, char * txFreq, char * rxFreq){ //Note: variable tracks failure so that false (0) maps to HAL_OK (also 0) bool failedConfig = false; @@ -46,7 +46,7 @@ HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, boo HAL_Delay(1000); //Now, set the parameters of the module - sprintf(transmitData, "AT+DMOSETGROUP=0,144.3900,144.3900,0000,0,0000\r\n"); + sprintf(transmitData, "AT+DMOSETGROUP=0,%s,%s,0000,0,0000\r\n", txFreq, rxFreq); HAL_UART_Transmit(&huart, (uint8_t*) transmitData, SET_PARAMETERS_TRANSMIT_LENGTH, HAL_MAX_DELAY); HAL_UART_Receive(&huart, (uint8_t*) responseData, SET_PARAMETERS_RESPONSE_LENGTH, HAL_MAX_DELAY); diff --git a/TagV3.0_U575VGT/Core/Src/app_threadx.c b/TagV3.0_U575VGT/Core/Src/app_threadx.c index b378a1e5..19f26c06 100644 --- a/TagV3.0_U575VGT/Core/Src/app_threadx.c +++ b/TagV3.0_U575VGT/Core/Src/app_threadx.c @@ -28,6 +28,7 @@ #include "main.h" #include "Recovery Inc/AprsTransmit.h" #include "Recovery Inc/VHF.h" +#include "Recovery Inc/Aprs.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -47,8 +48,8 @@ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ -TX_THREAD test_thread; -uint8_t thread_stack[THREAD_STACK_SIZE]; +TX_THREAD aprs_thread; +uint8_t aprs_thread_stack[THREAD_STACK_SIZE]; extern UART_HandleTypeDef huart4; extern uint8_t transmits; /* USER CODE END PV */ @@ -68,13 +69,13 @@ UINT App_ThreadX_Init(VOID *memory_ptr) { UINT ret = TX_SUCCESS; /* USER CODE BEGIN App_ThreadX_MEM_POOL */ - VOID * pointer = &thread_stack; + VOID * pointer = &aprs_thread_stack; // Allocate memory pool TX_BYTE_POOL* byte_pool = (TX_BYTE_POOL*) memory_ptr; ret = tx_byte_allocate(byte_pool, &pointer, THREAD_STACK_SIZE, TX_NO_WAIT); /* USER CODE END App_ThreadX_MEM_POOL */ /* USER CODE BEGIN App_ThreadX_Init */ - tx_thread_create(&test_thread, "Test_Thread", test_thread_entry, 0x1234, thread_stack, THREAD_STACK_SIZE, 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); + tx_thread_create(&aprs_thread, "APRS_Thread", aprs_thread_entry, 0x1234, aprs_thread_stack, THREAD_STACK_SIZE, 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); /* USER CODE END App_ThreadX_Init */ return ret; From 8d7fd907757071d9bcd36cce6dbc1726aaf0ffde Mon Sep 17 00:00:00 2001 From: kgrewal26 Date: Wed, 5 Jul 2023 16:05:35 -0400 Subject: [PATCH 2/5] helpful timing macro and random sleep intervals git push --- TagV3.0_U575VGT/Core/Inc/Lib Inc/timing.h | 24 +++++++++++++++++++ TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h | 6 +++-- .../Core/Inc/Recovery Inc/AprsTransmit.h | 3 ++- TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c | 9 ++++++- 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 TagV3.0_U575VGT/Core/Inc/Lib Inc/timing.h diff --git a/TagV3.0_U575VGT/Core/Inc/Lib Inc/timing.h b/TagV3.0_U575VGT/Core/Inc/Lib Inc/timing.h new file mode 100644 index 00000000..5738b592 --- /dev/null +++ b/TagV3.0_U575VGT/Core/Inc/Lib Inc/timing.h @@ -0,0 +1,24 @@ +/* + * timing.h + * + * Created on: Jul 5, 2023 + * Author: Kaveet + * + * A library file containing helpful functions, macros and constants related to timing. This could include RTOS Software Timers, delays, etc. + */ + +#ifndef INC_LIB_INC_TIMING_H_ +#define INC_LIB_INC_TIMING_H_ + +#include "tx_user.h" + +//A macro for converting seconds to threadX ticks. This can be used to feed into software timers, task sleeps, etc. +#define tx_s_to_ticks(S) ((S) * (TX_TIMER_TICKS_PER_SECOND)) + +//A macro for converting milliseconds to threadX ticks. This can be used to feed into software timers, task sleeps, etc. +#define tx_ms_to_ticks(MS) ((MS) * (TX_TIMER_TICKS_PER_SECOND) / 1000) + +//A macro for converting microseconds to threadX ticks. This can be used to feed into software timers, task sleeps, etc. +#define tx_us_to_ticks(US) ((US) * (TX_TIMER_TICKS_PER_SECOND) / 1000000) + +#endif /* INC_LIB_INC_TIMING_H_ */ diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h index b3ede882..c2588873 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h @@ -24,9 +24,11 @@ #define APRS_PACKET_LENGTH 224 -#define GPS_SLEEP_LENGTH 200000 +#define GPS_SLEEP_LENGTH tx_s_to_ticks(10) -#define APRS_BASE_SLEEP_LENGTH 1200000 +#define APRS_BASE_SLEEP_LENGTH tx_s_to_ticks(60) + +#define NUM_TX_ATTEMPTS 3 //Main thread entry void aprs_thread_entry(ULONG aprs_thread_input); diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h index 34d899be..b112761f 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h @@ -29,11 +29,12 @@ #include #include #include "tx_api.h" +#include "Lib Inc/timing.h" //Defines //The time to transmit each bit for //Each ThreadX tick is 50us -> 17 ticks makes it 850us. Based off the PICO code for the old recovery boards, where the bit time is 832us. -#define APRS_TRANSMIT_BIT_TIME 17 +#define APRS_TRANSMIT_BIT_TIME tx_us_to_ticks(850) //The hardware timer periods for 1200Hz and 2400Hz signals #define APRS_TRANSMIT_PERIOD_1200HZ 84 diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c index 54b934b8..79fa35c2 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c @@ -11,6 +11,7 @@ #include "Recovery Inc/AprsPacket.h" #include "Recovery Inc/AprsTransmit.h" #include "main.h" +#include //Extern variables for HAL UART handlers extern UART_HandleTypeDef huart4; @@ -61,7 +62,7 @@ void aprs_thread_entry(ULONG aprs_thread_input){ set_ptt(true); //Now, transmit the signal through the VHF module. Transmit a few times just for safety. - for (uint8_t transmits = 0; transmits < 3; transmits++){ + for (uint8_t transmits = 0; transmits < NUM_TX_ATTEMPTS; transmits++){ aprs_transmit_send_data(packetBuffer, APRS_PACKET_LENGTH); } @@ -70,6 +71,12 @@ void aprs_thread_entry(ULONG aprs_thread_input){ //Set the sleep period for a successful APRS transmission sleepPeriod = APRS_BASE_SLEEP_LENGTH; + + //Add a random component to it so that we dont transmit at the same interval each time (to prevent bad timing drowning out other transmissions) + uint8_t randomNum = rand() % 30; + + //Add a random amount of seconds to the sleep, from 0 to 29 + sleepPeriod += tx_s_to_ticks(randomNum); } //Go to sleep now From e559bda52186dad593d4503a519cebce87422bd6 Mon Sep 17 00:00:00 2001 From: kgrewal26 Date: Wed, 5 Jul 2023 16:39:58 -0400 Subject: [PATCH 3/5] code cleanup and styling --- TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h | 8 +-- TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c | 22 +++---- .../Core/Src/Recovery Src/AprsPacket.c | 42 ++++++------ .../Core/Src/Recovery Src/AprsTransmit.c | 26 ++++---- TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c | 20 +++--- TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c | 64 +++++++++---------- TagV3.0_U575VGT/Core/Src/app_threadx.c | 3 - 7 files changed, 91 insertions(+), 94 deletions(-) diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h index 15919de7..f3da2ca6 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h @@ -50,7 +50,7 @@ -huart - UART handler to talk to the module -isHigh: whether or not to use high power (1W) or low power (0.5W). Passing true means high power. */ -HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh, char * txFreq, char * rxFreq); +HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool is_high, char * tx_freq, char * rx_freq); /*Configure the VHF module over UART Parameters: @@ -60,13 +60,13 @@ HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh, char * t -lpf: Apply a low-pass-filter on the signals. -hps: Apply a high-pass-filter on the signals. */ -HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, bool lpf, bool hpf, char * txFreq, char * rxFreq); +HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, bool lpf, bool hpf, char * tx_freq, char * rx_freq); //Enables or disbles the push-to-talk pin. Setting true lets us talk to the module (i.e., transmit signals). -void set_ptt(bool isTx); +void set_ptt(bool is_tx); //Toggles the power level on the module from high (1W) and low (0.5W). -void set_power_level(bool isHigh); +void set_power_level(bool is_high); //Puts the VHF module to sleep void sleep_vhf(); diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c index 79fa35c2..44b6fc98 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c @@ -17,7 +17,7 @@ extern UART_HandleTypeDef huart4; extern UART_HandleTypeDef huart3; -static bool toggleFreq(bool is_gps_dominica, bool is_currently_dominica); +static bool toggle_freq(bool is_gps_dominica, bool is_currently_dominica); void aprs_thread_entry(ULONG aprs_thread_input){ @@ -33,7 +33,7 @@ void aprs_thread_entry(ULONG aprs_thread_input){ set_ptt(false); //We arent in dominica by default - bool isInDominica = false; + bool is_in_dominica = false; //Main task loop while(1){ @@ -42,21 +42,21 @@ void aprs_thread_entry(ULONG aprs_thread_input){ GPS_Data gps_data; //Attempt to get a GPS lock - bool isLocked = get_gps_lock(&gps, &gps_data); + bool is_locked = get_gps_lock(&gps, &gps_data); //The time we will eventually put this task to sleep for. We assign this assuming the GPS lock has failed (only sleep for a shorter, fixed period of time). //If we did get a GPS lock, the sleepPeriod will correct itself by the end of the task (be appropriately assigned after APRS transmission) - uint32_t sleepPeriod = GPS_SLEEP_LENGTH; + uint32_t sleep_period = GPS_SLEEP_LENGTH; //If we've locked onto a position, we can start creating an APRS packet. - if (isLocked){ + if (is_locked){ aprs_generate_packet(packetBuffer, gps_data.latitude, gps_data.longitude); //We first initialized the VHF module with our default frequencies. If we are in Dominica, re-initialize the VHF module to use the dominica frequencies. // //The function also handles switching back to the default frequency if we leave dominica - isInDominica = toggleFreq(gps_data.is_dominica, isInDominica); + is_in_dominica = toggle_freq(gps_data.is_dominica, is_in_dominica); //Start transmission set_ptt(true); @@ -70,17 +70,17 @@ void aprs_thread_entry(ULONG aprs_thread_input){ set_ptt(false); //Set the sleep period for a successful APRS transmission - sleepPeriod = APRS_BASE_SLEEP_LENGTH; + sleep_period = APRS_BASE_SLEEP_LENGTH; //Add a random component to it so that we dont transmit at the same interval each time (to prevent bad timing drowning out other transmissions) - uint8_t randomNum = rand() % 30; + uint8_t random_num = rand() % 30; //Add a random amount of seconds to the sleep, from 0 to 29 - sleepPeriod += tx_s_to_ticks(randomNum); + sleep_period += tx_s_to_ticks(random_num); } //Go to sleep now - tx_thread_sleep(sleepPeriod); + tx_thread_sleep(sleep_period); } } @@ -91,7 +91,7 @@ void aprs_thread_entry(ULONG aprs_thread_input){ * * Returns: the current state of our configuration (whether or not VHF is configured for dominica */ -static bool toggleFreq(bool is_gps_dominica, bool is_currently_dominica){ +static bool toggle_freq(bool is_gps_dominica, bool is_currently_dominica){ //If the GPS is in dominica, but we are not configured for it, switch to dominica if (is_gps_dominica && !is_currently_dominica){ diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsPacket.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsPacket.c index ecf8c932..b3459275 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsPacket.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsPacket.c @@ -88,65 +88,65 @@ static void append_gps_data(uint8_t * buffer, float lat, float lon){ buffer[0] = APRS_DT_POS_CHARACTER; //First, create the string containing the latitude and longitude data, then save it into our buffer - bool isNorth = true; + bool is_north = true; //If we have a negative value, then the location is in the southern hemisphere. //Recognize this and then just use the magnitude of the latitude for future calculations. if (lat < 0){ - isNorth = false; - isNorth *= -1; + is_north = false; + is_north *= -1; } //The coordinates we get from the GPS are in degrees and fractional degrees //We need to extract the whole degrees from this, then the whole minutes and finally the fractional minutes //The degrees are just the rounded-down integer - uint8_t latDegWhole = (uint8_t) lat; + uint8_t lat_deg_whole = (uint8_t) lat; //Find the remainder (fractional degrees) and multiply it by 60 to get the minutes (fractional and whole) - float latMinutes = (lat - latDegWhole) * 60; + float lat_minutes = (lat - lat_deg_whole) * 60; //Whole number minutes is just the fractional component. - uint8_t latMinutesWhole = (uint8_t) latMinutes; + uint8_t lat_minutes_whole = (uint8_t) lat_minutes; //Find the remainder (fractional component) and save it to two decimal points (multiply by 100 and cast to int) - uint8_t latMinutesFrac = (latMinutes - latMinutesWhole) * 100; + uint8_t lat_minutes_frac = (lat_minutes - lat_minutes_whole) * 100; //Find our direction indicator (N for North of S for south) - char latDirection = (isNorth) ? 'N' : 'S'; + char lat_direction = (is_north) ? 'N' : 'S'; //Create our string. We use the format ddmm.hh(N/S), where "d" is degrees, "m" is minutes and "h" is fractional minutes. //Store this in our buffer. - snprintf(&buffer[1], APRS_LATITUDE_LENGTH, "%02d%02d.%02d%c", latDegWhole, latMinutesWhole, latMinutesFrac, latDirection); + snprintf(&buffer[1], APRS_LATITUDE_LENGTH, "%02d%02d.%02d%c", lat_deg_whole, lat_minutes_whole, lat_minutes_frac, lat_direction); //Right now we have the null-terminating character in the buffer "\0". Replace this with our latitude and longitude seperating symbol "1". buffer[APRS_LATITUDE_LENGTH] = APRS_SYM_TABLE_CHAR; //Now, repeat the process for longitude. - bool isEast = true; + bool is_east = true; //If its less than 0, remember it as West, and then take the magnitude if (lon < 0){ - isEast = false; + is_east = false; lon *= -1; } //Find whole number degrees - uint8_t lonDegWhole = (uint8_t) lon; + uint8_t lon_deg_whole = (uint8_t) lon; //Find remainder (fractional degrees), convert to minutes - float lonMinutes = (lon - lonDegWhole) * 60; + float lon_minutes = (lon - lon_deg_whole) * 60; //Find whole number and fractional minutes. Take two decimal places for the fractional minutes, just like before - uint8_t lonMinutesWhole = (uint8_t) lonMinutes; - uint8_t lonMinutesFractional = (lonMinutes - lonMinutesWhole) * 100; + uint8_t lon_minutes_whole = (uint8_t) lon_minutes; + uint8_t lon_minutes_fractional = (lon_minutes - lon_minutes_whole) * 100; //Find direction character - char lonDirection = (isEast) ? 'E' : 'W'; + char lon_direction = (is_east) ? 'E' : 'W'; //Store this in the buffer, in the format dddmm.hh(E/W) - snprintf(&buffer[APRS_LATITUDE_LENGTH + 1], APRS_LONGITUDE_LENGTH, "%03d%02d.%02d%c", lonDegWhole, lonMinutesWhole, lonMinutesFractional, lonDirection); + snprintf(&buffer[APRS_LATITUDE_LENGTH + 1], APRS_LONGITUDE_LENGTH, "%03d%02d.%02d%c", lon_deg_whole, lon_minutes_whole, lon_minutes_fractional, lon_direction); //Appending payload character indicating the APRS symbol (using boat symbol). Replace the null-terminating character with it. buffer[APRS_LATITUDE_LENGTH + APRS_LONGITUDE_LENGTH] = APRS_SYM_CODE_CHAR; @@ -185,10 +185,10 @@ static void append_frame_check(uint8_t * buffer, uint8_t buffer_length){ } } - uint8_t crcLo = (crc & 0xFF) ^ 0xFF; - uint8_t crcHi = (crc >> 8) ^ 0xFF; + uint8_t crc_lo = (crc & 0xFF) ^ 0xFF; + uint8_t crc_hi = (crc >> 8) ^ 0xFF; - buffer[buffer_length] = crcLo; - buffer[buffer_length + 1] = crcHi; + buffer[buffer_length] = crc_lo; + buffer[buffer_length + 1] = crc_hi; } diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsTransmit.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsTransmit.c index 4ba027f2..6b43702a 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsTransmit.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/AprsTransmit.c @@ -13,8 +13,8 @@ static void calcSineValues(); //Private variables -static bool byteCompleteFlag; -static bool is1200Hz = false; +static bool byte_complete_flag; +static bool is_1200_hz = false; //Extern variables extern DAC_HandleTypeDef hdac1; @@ -37,13 +37,13 @@ bool aprs_transmit_send_data(uint8_t * packet_data, uint16_t packet_length){ for (int byte_index = 0; byte_index < packet_length; byte_index++){ //Set complete flag to false so we can poll it later - byteCompleteFlag = false; + byte_complete_flag = false; //Create a timer to control the transmission of each bit. We pass in the current byte as an input to the timer so it can iterate over it bit by bit. tx_timer_create(&bit_timer, "APRS Transmit Bit Timer", aprs_transmit_bit_timer_entry, packet_data[byte_index], APRS_TRANSMIT_BIT_TIME, APRS_TRANSMIT_BIT_TIME, TX_AUTO_ACTIVATE); //Poll for completion of the byte - while (!byteCompleteFlag); + while (!byte_complete_flag); //Delete the timer so we can recreate it later with the next byte as an input @@ -56,7 +56,7 @@ bool aprs_transmit_send_data(uint8_t * packet_data, uint16_t packet_length){ //Reset the timer period for the next transmission MX_TIM2_Fake_Init(APRS_TRANSMIT_PERIOD_2400HZ); - is1200Hz = false; + is_1200_hz = false; return true; } @@ -66,21 +66,21 @@ void aprs_transmit_bit_timer_entry(ULONG bit_timer_input){ //static variable to keep track of our bit index static uint8_t bit_index = 0; static uint8_t bit_stuff_counter = 0; - static bool isStuffedBit = false; + static bool is_stuffed_bit = false; //Current byte we will iterate over uint8_t current_byte = (uint8_t) bit_timer_input; if (bit_stuff_counter >= 5){ - isStuffedBit = true; + is_stuffed_bit = true; } //Check if the current bit is 0 - if (!aprs_transmit_read_bit(current_byte, bit_index) || isStuffedBit){ + if (!aprs_transmit_read_bit(current_byte, bit_index) || is_stuffed_bit){ //Since the bit is 0, switch the frequency - uint8_t newPeriod = (is1200Hz) ? (APRS_TRANSMIT_PERIOD_2400HZ) : (APRS_TRANSMIT_PERIOD_1200HZ); - is1200Hz = !is1200Hz; + uint8_t newPeriod = (is_1200_hz) ? (APRS_TRANSMIT_PERIOD_2400HZ) : (APRS_TRANSMIT_PERIOD_1200HZ); + is_1200_hz = !is_1200_hz; //Use fake init function to re-initialize the timer with a new period MX_TIM2_Fake_Init(newPeriod); @@ -91,16 +91,16 @@ void aprs_transmit_bit_timer_entry(ULONG bit_timer_input){ } - if (!isStuffedBit){ + if (!is_stuffed_bit){ //increment bit index bit_index++; }else { - isStuffedBit = false; + is_stuffed_bit = false; } //If we've iterated through all bits, set flag and reset index counter if (bit_index >= BITS_PER_BYTE){ - byteCompleteFlag = true; + byte_complete_flag = true; bit_index = 0; } } diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c index c05605fa..c66fa596 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c @@ -28,7 +28,7 @@ HAL_StatusTypeDef initialize_gps(UART_HandleTypeDef* huart, GPS_HandleTypeDef* g bool read_gps_data(GPS_HandleTypeDef* gps){ - uint8_t receiveBuffer[256] = {0}; + uint8_t receive_buffer[256] = {0}; if (GPS_SIMULATION){ @@ -44,17 +44,17 @@ bool read_gps_data(GPS_HandleTypeDef* gps){ return true; } - HAL_UART_Receive(gps->huart, receiveBuffer, 1, GPS_UART_TIMEOUT); + HAL_UART_Receive(gps->huart, receive_buffer, 1, GPS_UART_TIMEOUT); - if (receiveBuffer[0] == GPS_PACKET_START_CHAR){ + if (receive_buffer[0] == GPS_PACKET_START_CHAR){ uint8_t read_index = 0; - while (receiveBuffer[read_index] != GPS_PACKET_END_CHAR){ + while (receive_buffer[read_index] != GPS_PACKET_END_CHAR){ read_index++; - HAL_UART_Receive(gps->huart, &receiveBuffer[read_index], 1, GPS_UART_TIMEOUT); + HAL_UART_Receive(gps->huart, &receive_buffer[read_index], 1, GPS_UART_TIMEOUT); } - parse_gps_output(gps, receiveBuffer, read_index + 1); + parse_gps_output(gps, receive_buffer, read_index + 1); return true; } @@ -185,13 +185,13 @@ bool get_gps_lock(GPS_HandleTypeDef* gps, GPS_Data* gps_data){ } //time trackers for any possible timeouts - uint32_t startTime = HAL_GetTick(); - uint32_t currentTime = startTime; + uint32_t start_time = HAL_GetTick(); + uint32_t current_time = start_time; //Keep trying to read the GPS data until we get a lock, or we timeout - while (!gps->is_pos_locked && ((currentTime - startTime) < GPS_TRY_LOCK_TIMEOUT)){ + while (!gps->is_pos_locked && ((current_time - start_time) < GPS_TRY_LOCK_TIMEOUT)){ read_gps_data(gps); - currentTime = HAL_GetTick(); + current_time = HAL_GetTick(); } //Populate the GPS data struct that we are officially returning to the caller. Prioritize message types in the order they appear in the enum definiton diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c index 8d65919b..a3ba033a 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/VHF.c @@ -9,94 +9,94 @@ #include #include -HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool isHigh, char * txFreq, char * rxFreq){ +HAL_StatusTypeDef initialize_vhf(UART_HandleTypeDef huart, bool is_high, char * tx_freq, char * rx_freq){ //Set the modes of the GPIO pins attached to the vhf module. //Leave PTT floating, set appropriate power level and wake chip HAL_Delay(1000); set_ptt(true); - set_power_level(isHigh); + set_power_level(is_high); wake_vhf(); HAL_Delay(1000); - return configure_dra818v(huart, false, false, false, txFreq, rxFreq); + return configure_dra818v(huart, false, false, false, tx_freq, rx_freq); } -HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, bool lpf, bool hpf, char * txFreq, char * rxFreq){ +HAL_StatusTypeDef configure_dra818v(UART_HandleTypeDef huart, bool emphasis, bool lpf, bool hpf, char * tx_freq, char * rx_freq){ //Note: variable tracks failure so that false (0) maps to HAL_OK (also 0) - bool failedConfig = false; + bool failed_config = false; //Data buffer to hold transmissions and responses - char transmitData[100]; - char responseData[100]; + char transmit_data[100]; + char response_data[100]; HAL_Delay(1000); //Start with the VHF handshake to confirm module is setup correctly - sprintf(transmitData, "AT+DMOCONNECT \r\n"); + sprintf(transmit_data, "AT+DMOCONNECT \r\n"); - HAL_UART_Transmit(&huart, (uint8_t*) transmitData, HANDSHAKE_TRANSMIT_LENGTH, HAL_MAX_DELAY); - HAL_UART_Receive(&huart, (uint8_t*) responseData, HANDSHAKE_RESPONSE_LENGTH, HAL_MAX_DELAY); + HAL_UART_Transmit(&huart, (uint8_t*) transmit_data, HANDSHAKE_TRANSMIT_LENGTH, HAL_MAX_DELAY); + HAL_UART_Receive(&huart, (uint8_t*) response_data, HANDSHAKE_RESPONSE_LENGTH, HAL_MAX_DELAY); //Ensure the response matches the expected response - if (strncmp(responseData, VHF_HANDSHAKE_EXPECTED_RESPONSE, HANDSHAKE_RESPONSE_LENGTH) != 0) - failedConfig = true; + if (strncmp(response_data, VHF_HANDSHAKE_EXPECTED_RESPONSE, HANDSHAKE_RESPONSE_LENGTH) != 0) + failed_config = true; HAL_Delay(1000); //Now, set the parameters of the module - sprintf(transmitData, "AT+DMOSETGROUP=0,%s,%s,0000,0,0000\r\n", txFreq, rxFreq); + sprintf(transmit_data, "AT+DMOSETGROUP=0,%s,%s,0000,0,0000\r\n", tx_freq, rx_freq); - HAL_UART_Transmit(&huart, (uint8_t*) transmitData, SET_PARAMETERS_TRANSMIT_LENGTH, HAL_MAX_DELAY); - HAL_UART_Receive(&huart, (uint8_t*) responseData, SET_PARAMETERS_RESPONSE_LENGTH, HAL_MAX_DELAY); + HAL_UART_Transmit(&huart, (uint8_t*) transmit_data, SET_PARAMETERS_TRANSMIT_LENGTH, HAL_MAX_DELAY); + HAL_UART_Receive(&huart, (uint8_t*) response_data, SET_PARAMETERS_RESPONSE_LENGTH, HAL_MAX_DELAY); //Ensure the response matches the expected response - if (strncmp(responseData, VHF_SET_PARAMETERS_EXPECTED_RESPONSE, SET_PARAMETERS_RESPONSE_LENGTH) != 0) - failedConfig = true; + if (strncmp(response_data, VHF_SET_PARAMETERS_EXPECTED_RESPONSE, SET_PARAMETERS_RESPONSE_LENGTH) != 0) + failed_config = true; HAL_Delay(1000); //Set the volume of the transmissions - sprintf(transmitData, "AT+DMOSETVOLUME=%d\r\n", VHF_VOLUME_LEVEL); + sprintf(transmit_data, "AT+DMOSETVOLUME=%d\r\n", VHF_VOLUME_LEVEL); - HAL_UART_Transmit(&huart, (uint8_t*) transmitData, SET_VOLUME_TRANSMIT_LENGTH, HAL_MAX_DELAY); - HAL_UART_Receive(&huart, (uint8_t*) responseData, SET_VOLUME_RESPONSE_LENGTH, HAL_MAX_DELAY); + HAL_UART_Transmit(&huart, (uint8_t*) transmit_data, SET_VOLUME_TRANSMIT_LENGTH, HAL_MAX_DELAY); + HAL_UART_Receive(&huart, (uint8_t*) response_data, SET_VOLUME_RESPONSE_LENGTH, HAL_MAX_DELAY); //Ensure the response matches the expected response - if (strncmp(responseData, VHF_SET_VOLUME_EXPECTED_RESPONSE, SET_VOLUME_RESPONSE_LENGTH) != 0) - failedConfig = true; + if (strncmp(response_data, VHF_SET_VOLUME_EXPECTED_RESPONSE, SET_VOLUME_RESPONSE_LENGTH) != 0) + failed_config = true; HAL_Delay(1000); //Set the filter parameters //Invert all the bools passed in since the VHF module treats "0" as true - sprintf(transmitData, "AT+SETFILTER=%d,%d,%d\r\n", emphasis, hpf, lpf); + sprintf(transmit_data, "AT+SETFILTER=%d,%d,%d\r\n", emphasis, hpf, lpf); - HAL_UART_Transmit(&huart, (uint8_t*) transmitData, SET_FILTER_TRANSMIT_LENGTH, HAL_MAX_DELAY); - HAL_UART_Receive(&huart, (uint8_t*) responseData, SET_FILTER_RESPONSE_LENGTH, HAL_MAX_DELAY); + HAL_UART_Transmit(&huart, (uint8_t*) transmit_data, SET_FILTER_TRANSMIT_LENGTH, HAL_MAX_DELAY); + HAL_UART_Receive(&huart, (uint8_t*) response_data, SET_FILTER_RESPONSE_LENGTH, HAL_MAX_DELAY); //Ensure the response matches the expected response - if (strncmp(responseData, VHF_SET_FILTER_EXPECTED_RESPONSE, SET_FILTER_RESPONSE_LENGTH) != 0) - failedConfig = true; + if (strncmp(response_data, VHF_SET_FILTER_EXPECTED_RESPONSE, SET_FILTER_RESPONSE_LENGTH) != 0) + failed_config = true; HAL_Delay(1000); - return failedConfig; + return failed_config; } -void set_ptt(bool isTx){ +void set_ptt(bool is_tx){ //isTx determines if the GPIO is high or low, and thus if we are transmitting or not - HAL_GPIO_WritePin(VHF_PTT_GPIO_Port, VHF_PTT_Pin, isTx); + HAL_GPIO_WritePin(VHF_PTT_GPIO_Port, VHF_PTT_Pin, is_tx); } -void set_power_level(bool isHigh){ +void set_power_level(bool is_high){ //isHigh determines if we should use high power (1W) or low (0.5W) - HAL_GPIO_WritePin(APRS_H_L_GPIO_Port, APRS_H_L_Pin, isHigh); + HAL_GPIO_WritePin(APRS_H_L_GPIO_Port, APRS_H_L_Pin, is_high); } diff --git a/TagV3.0_U575VGT/Core/Src/app_threadx.c b/TagV3.0_U575VGT/Core/Src/app_threadx.c index 19f26c06..fa7cad3b 100644 --- a/TagV3.0_U575VGT/Core/Src/app_threadx.c +++ b/TagV3.0_U575VGT/Core/Src/app_threadx.c @@ -50,14 +50,11 @@ /* USER CODE BEGIN PV */ TX_THREAD aprs_thread; uint8_t aprs_thread_stack[THREAD_STACK_SIZE]; -extern UART_HandleTypeDef huart4; -extern uint8_t transmits; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ void test_thread_entry(ULONG thread_input); -void timer_entry(ULONG timer_input); /* USER CODE END PFP */ /** From 4c8d8b7a7419ccc07f62dab8b9958246bc496b4e Mon Sep 17 00:00:00 2001 From: kgrewal26 Date: Wed, 5 Jul 2023 16:52:18 -0400 Subject: [PATCH 4/5] more comments --- TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h | 18 +++++++++------- .../Core/Inc/Recovery Inc/AprsPacket.h | 6 ++++++ .../Core/Inc/Recovery Inc/AprsTransmit.h | 21 +++++++++---------- TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h | 1 - TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h | 5 +++++ TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c | 2 +- 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h index c2588873..f5b72c3c 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/Aprs.h @@ -3,20 +3,22 @@ * * Created on: May 26, 2023 * Author: Kaveet + * + * This file contains the main APRS thread responsible for board recovery. + * + * It receives the GPS data from the GPS functions, and then calls the appropriate library functions + * to break up the data into an array and transmit it to the VHF module + * + * Library Functions/Files: + * - AprsTransmit -> handles the transmission of the sine wave + * - AprsPacket -> breaks the GPS data into appropriate packets */ #ifndef INC_RECOVERY_INC_APRS_H_ #define INC_RECOVERY_INC_APRS_H_ /* - * This file contains the main APRS thread responsible for board recovery. - * - * It receives the GPS data from the GPS functions, and then calls the appropriate library functions - * to break up the data into an array and transmit it to the VHF module - * - * Library Functions/Files: - * - AprsTransmit -> handles the transmission of the sine wave - * - AprsPacket -> breaks the GPS data into appropriate packets + */ #include "tx_api.h" diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsPacket.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsPacket.h index 84bad439..646af3d8 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsPacket.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsPacket.h @@ -3,6 +3,12 @@ * * Created on: Jul 5, 2023 * Author: Kaveet + * + * This file contains the appropriate functions and definitons to create an APRS packet. Requires the caller to pass in a buffer and the latitude and longitude. + * + * There are various static functions defined in the C file to help create this packet. + * + * The APRS task should call this after it receives its GPS data. It will then use this packet to transmit through the VHF module. */ #ifndef INC_RECOVERY_INC_APRSPACKET_H_ diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h index b112761f..2f53b88c 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/AprsTransmit.h @@ -3,28 +3,27 @@ * * Created on: May 26, 2023 * Author: Kaveet - */ - -#ifndef INC_RECOVERY_INC_APRSTRANSMIT_H_ -#define INC_RECOVERY_INC_APRSTRANSMIT_H_ - - -/* + * * This file handles the transmission of the APRS sine wave to the VHF module. * * This includes: - * - Tell the VHF module we will start talking to it - * - Generate the sine wave and appropriately apply the frequency modulation to it + * - Generating the sine wave and appropriately apply the frequency modulation to it * * Parameters: * - The raw data array to transmit (received from main APRS task) * + * It uses the DAC to transmit a sine wave through DMA. The frequency of the wave is controlled by a hardware timer (changing the period changes the frequency). + * + * There is a software timer that cycles through bits, changing the frequency appropriately. * - * Returns: - * - Whether or not the transmission was successful + * A "0" bit indicates a change in frequency, while a "1" bit will keep the same frequency. We toggle between 1200 and 2200 Hz. * + * During the main data/payload, there must be a stuffed bit (forced transition) after 5 consecutive 1's. */ +#ifndef INC_RECOVERY_INC_APRSTRANSMIT_H_ +#define INC_RECOVERY_INC_APRSTRANSMIT_H_ + //Includes #include #include diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h index 6966e223..ccf78573 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h @@ -12,7 +12,6 @@ * * Integration Manual: https://content.u-blox.com/sites/default/files/NEO-M9N_Integrationmanual_UBX-19014286.pdf * Interface Description: https://content.u-blox.com/sites/default/files/u-blox-M9-SPG-4.04_InterfaceDescription_UBX-21022436.pdf - * */ #ifndef INC_RECOVERY_INC_GPS_H_ diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h index f3da2ca6..e7d480ac 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/VHF.h @@ -7,6 +7,8 @@ * This file outlines the UART driver for the VHF module (DRA818V). * * It initializes, configures and manages the VHF module used in recovery mode. + * + * The VHF module attached our input signal (DAC) to the carrier wave. The carrier wave has a configurable frequency. */ #ifndef INC_RECOVERY_INC_VHF_H_ @@ -16,10 +18,13 @@ #include //Defines + +//Useful Frequencies #define TX_FREQ "144.3900" #define RX_FREQ "144.3900" #define DOMINICA_TX_FREQ "145.0500" #define DOMINICA_RX_FREQ "145.0500" + #define VHF_VOLUME_LEVEL 4 //Lengths of messages used to configure the VHF module diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c index 44b6fc98..b529c776 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/Aprs.c @@ -45,7 +45,7 @@ void aprs_thread_entry(ULONG aprs_thread_input){ bool is_locked = get_gps_lock(&gps, &gps_data); //The time we will eventually put this task to sleep for. We assign this assuming the GPS lock has failed (only sleep for a shorter, fixed period of time). - //If we did get a GPS lock, the sleepPeriod will correct itself by the end of the task (be appropriately assigned after APRS transmission) + //If we did get a GPS lock, the sleep_period will correct itself by the end of the task (be appropriately assigned after succesful APRS transmission) uint32_t sleep_period = GPS_SLEEP_LENGTH; //If we've locked onto a position, we can start creating an APRS packet. From f1529db67db844c4254f3b116f4f3d46e77e9c8d Mon Sep 17 00:00:00 2001 From: kgrewal26 Date: Wed, 5 Jul 2023 17:49:00 -0400 Subject: [PATCH 5/5] fixed is_in_dominica --- TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h | 2 ++ TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h index ccf78573..a102324d 100644 --- a/TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h +++ b/TagV3.0_U575VGT/Core/Inc/Recovery Inc/GPS.h @@ -34,6 +34,8 @@ #define DEFAULT_LAT 15.31383 #define DEFAULT_LON -61.30075 +#define DOMINICA_LAT_BOUNDARY 17.71468 + typedef enum __GPS_MESSAGE_TYPES { GPS_SIM = 0, GPS_GLL = 1, diff --git a/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c b/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c index c66fa596..76b4af62 100644 --- a/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c +++ b/TagV3.0_U575VGT/Core/Src/Recovery Src/GPS.c @@ -211,7 +211,6 @@ bool get_gps_lock(GPS_HandleTypeDef* gps, GPS_Data* gps_data){ return false; } -//TODO: implement properly bool is_in_dominica(float latitude, float longitude){ - return false; + return (latitude < DOMINICA_LAT_BOUNDARY); }