diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ BUILD_NUMBER ?= 0 # SOURCES: list of sources in the user application -SOURCES = main.c adc.c gpio.c i2c.c interrupts.c usart.c gps.c system_stm32f0xx.c +SOURCES = main.c adc.c gpio.c i2c.c interrupts.c uart.c gps.c system_stm32f0xx.c system.c wspr.c # TARGET: name of the user application TARGET = wsprhab-b$(BUILD_NUMBER) diff --git a/inc/gps.h b/inc/gps.h --- a/inc/gps.h +++ b/inc/gps.h @@ -40,32 +40,20 @@ enum gps_state GPS_STATE_NOFIX }; -// Messages (REMOVEME?) -#define GGA_MESSAGE -#define RMC_MESSAGE -#define UKN_MESSAGE + +void gps_init(); + +void gps_update_position(); +void gps_update_time(uint8_t* hour, uint8_t* minute, uint8_t* second); +void gps_check_lock(uint8_t* lock, uint8_t* sats); +uint8_t gps_check_nav(void); + void gps_poweron(void); void gps_poweroff(void); -void gps_init(void); -void gps_sendubx(uint8_t* data, uint8_t size); -char* get_longitudeTrimmed(void); -char* get_longitudeLSBs(void); -char* get_latitudeTrimmed(void); -char* get_latitudeLSBs(void); -char* get_timestamp(void); -char* get_gpsaltitude(void); -char* get_speedKnots(void); -char* get_course(void); -char* get_hdop(void); -uint16_t get_hdop_int_tenths(void); -char* get_sv(void); -char* get_dayofmonth(void); -uint8_t gps_hasfix(void); -void gps_process(void); + +void gps_acquirefix(void); uint8_t gps_getstate(void); -void gps_acquirefix(void); -void parse_gps_transmission(void); -void XORbyteWithChecksum(uint8_t byte); + #endif /* GPS_H_ */ diff --git a/inc/system.h b/inc/system.h new file mode 100644 --- /dev/null +++ b/inc/system.h @@ -0,0 +1,9 @@ +#ifndef _SYSTEM_H +#define _SYSTEM_H + +// Prototypes +void sysclk_init(void); +void enter_sleep(void); +void enter_deepsleep(void); + +#endif diff --git a/inc/usart.h b/inc/uart.h rename from inc/usart.h rename to inc/uart.h diff --git a/inc/wspr.h b/inc/wspr.h new file mode 100644 --- /dev/null +++ b/inc/wspr.h @@ -0,0 +1,11 @@ +#ifndef _WSPR_H +#define _WSPR_H + +// Prototypes +void wspr_init(void); +void wspr_sleep(void); +void wspr_wakeup(void); +void wspr_transmit(void); + + +#endif diff --git a/src/gps.c b/src/gps.c --- a/src/gps.c +++ b/src/gps.c @@ -4,203 +4,42 @@ #include "config.h" #include "gpio.h" -#include "usart.h" +#include "uart.h" #include "gps.h" -// Circular buffer for incoming data -uint8_t nmeaBuffer[NMEABUFFER_SIZE]; -// Location of parser in the buffer -uint8_t nmeaBufferParsePosition = 0; - -uint8_t skipBytes = 0; - -//used to index data arrays during data collection -uint32_t numBytes = 0; - -//variables to store data from transmission -//least significant digit is stored at location 0 of arrays -char tramsmissionType[7]; +typedef struct _gps_data +{ + int32_t hdop; + int32_t sats_in_view; + int32_t speed; + int32_t heading; -void gps_poweron(void) -{ - // NOTE: pchannel - HAL_GPIO_WritePin(GPS_NOTEN, 0); - uart_init(); - - // Begin DMA reception - HAL_UART_Receive_DMA(uart_gethandle(), nmeaBuffer, NMEABUFFER_SIZE); - -} - -void gps_poweroff(void) -{ - // NOTE: pchannel - uart_deinit(); - HAL_GPIO_WritePin(GPS_NOTEN, 1); -} + int32_t latitude; + int32_t longitude; + int32_t altitude; -char timestamp[12]; //hhmmss.ss -char* get_timestamp() -{ - return timestamp; -} - -char latitude[14]; //lllll.lla -char latitudeTmpTRIM[8]; -char latitudeTmpLSB[4]; -char* get_latitudeTrimmed() -{ - strncpy(latitudeTmpTRIM, &latitude[0], 7); - latitudeTmpTRIM[7] = 0x00; - return latitudeTmpTRIM; -} -char* get_latitudeLSBs() -{ - strncpy(latitudeTmpLSB, &latitude[7], 3); - latitudeTmpLSB[3] = 0x00; - return latitudeTmpLSB; -} - -char longitude[14]; //yyyyy.yyb -char longitudeTmpTRIM[9]; -char longitudeTmpLSB[4]; + uint8_t hour; + uint8_t minute; + uint8_t second; -char* get_longitudeTrimmed() -{ - strncpy(longitudeTmpTRIM, &longitude[0], 8); - longitudeTmpTRIM[8] = 0x00; - return longitudeTmpTRIM; -} -char* get_longitudeLSBs() -{ - strncpy(longitudeTmpLSB, &longitude[8], 3); - longitudeTmpLSB[3] = 0x00; - return longitudeTmpLSB; -} +} gps_data_t; -char quality; //quality for GGA and validity for RMC -char numSatellites[4]; -char* get_sv() -{ - return numSatellites; -} - -char hdop[6]; //xx.x -char* get_hdop() -{ - return hdop; -} +gps_data_t position; -uint16_t get_hdop_int_tenths(void) -{ - // If only one digit before decimal - if(hdop[1] == '.') - { - return (hdop[0]-0x30)*10 + (hdop[2]-0x30); - } - - // Return normal hdop - return (hdop[0]-0x30)*100 + (hdop[1]-0x30)*10 + (hdop[2]-0x30); -} - -char altitude[10]; //xxxxxx.x -char* get_gpsaltitude() -{ - return altitude; -} - -//char wgs84Height[8]; //sxxx.x -//char lastUpdated[8]; //blank - included for testing -//char stationID[8]; //blank - included for testing -char checksum[3]; //xx - -char knots[8]; //xxx.xx -char* get_speedKnots() -{ - return knots; -} - -char course[8]; //xxx.x -char* get_course() -{ - return course; -} - -char dayofmonth[9]; //ddmmyy -char* get_dayofmonth() -{ - return dayofmonth; -} +// Private methods +static void gps_ubx_checksum(uint8_t* data, uint8_t len, uint8_t* cka, uint8_t* ckb); +static uint8_t _gps_verify_checksum(uint8_t* data, uint8_t len); -uint8_t gps_hadfix = 0; -uint8_t gps_hasfix() -{ - uint8_t hasFix = get_latitudeTrimmed()[0] != 0x00; - gps_hadfix = hasFix; - return hasFix; -} - -//char variation[9]; //xxx.xb -int calculatedChecksum; -int receivedChecksum; - -// transmission state machine -enum decodeState { - //shared fields - INITIALIZE=0, - GET_TYPE, - GPS_CHECKSUM, //XOR of all the bytes between the $ and the * (not including the delimiters themselves), written in hexadecimal - //GGA data fields - GGA_TIME, - GGA_LATITUDE, - GGA_LONGITUDE, - GGA_QUALITY, - GGA_SATELLITES, - GGA_HDOP, - GGA_ALTITUDE, - GGA_WGS84, - GGA_LAST_UPDATE, - GGA_STATION_ID, - //RMC data fields - RMC_TIME, - RMC_VALIDITY, - RMC_LATITUDE, - RMC_LONGITUDE, - RMC_KNOTS, - RMC_COURSE, - RMC_DATE, - RMC_MAG_VARIATION, - -}decodeState; - -// -//void usart1_isr(void) -//{ -// uint8_t recv = 0;// usart_recv(GPS_USART); -// //ECHO debug: usart_send_blocking(GPS_USART, recv); -// nmeaBuffer[nmeaBufferDataPosition % NMEABUFFER_SIZE] = recv; -// nmeaBufferDataPosition = (nmeaBufferDataPosition + 1) % NMEABUFFER_SIZE; -//} - -void gps_init() +void gps_init() { // Initialize serial port // done in poweron uart_init(); - timestamp[0] = 0x00; - latitude[0] = 0x00; - longitude[0] = 0x00; - numSatellites[0] = 0x00; - hdop[0] = 0x00; - knots[0] = 0x00; - course[0] = 0x00; - dayofmonth[0] = 0x00; - // // Disable GLONASS mode // uint8_t disable_glonass[20] = {0xB5, 0x62, 0x06, 0x3E, 0x0C, 0x00, 0x00, 0x00, 0x20, 0x01, 0x06, 0x08, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x01, 0x8F, 0xB2}; // @@ -217,69 +56,203 @@ void gps_init() } -void gps_sendubx(uint8_t* dat, uint8_t size) + +void gps_update_position() +{ + // Request a NAV-POSLLH message from the GPS + uint8_t request[8] = {0xB5, 0x62, 0x01, 0x02, 0x00, 0x00, 0x03, + 0x0A}; + //_gps_send_msg(request, 8); + HAL_UART_Transmit(uart_gethandle(), request, 8, 100); + + uint8_t buf[36]; + HAL_UART_Receive(uart_gethandle(), buf, 36, 100); + + //for(uint8_t i = 0; i < 36; i++) + // buf[i] = _gps_get_byte(); + +// // Verify the sync and header bits +// if( buf[0] != 0xB5 || buf[1] != 0x62 ) +// led_set(LED_RED, 1); +// if( buf[2] != 0x01 || buf[3] != 0x02 ) +// led_set(LED_RED, 1); + + // 4 bytes of longitude (1e-7) + position.longitude = (int32_t)buf[10] | (int32_t)buf[11] << 8 | + (int32_t)buf[12] << 16 | (int32_t)buf[13] << 24; + + // 4 bytes of latitude (1e-7) + position.latitude = (int32_t)buf[14] | (int32_t)buf[15] << 8 | + (int32_t)buf[16] << 16 | (int32_t)buf[17] << 24; + + // 4 bytes of altitude above MSL (mm) + position.altitude = (int32_t)buf[22] | (int32_t)buf[23] << 8 | + (int32_t)buf[24] << 16 | (int32_t)buf[25] << 24; + + //if( !_gps_verify_checksum(&buf[2], 32) ) led_set(LED_RED, 1); +} + + +void gps_update_time(uint8_t* hour, uint8_t* minute, uint8_t* second) +{ + // Send a NAV-TIMEUTC message to the receiver + uint8_t request[8] = {0xB5, 0x62, 0x01, 0x21, 0x00, 0x00, + 0x22, 0x67}; + HAL_UART_Transmit(uart_gethandle(), request, 8, 100); + + // Get the message back from the GPS + uint8_t buf[28]; + HAL_UART_Receive(uart_gethandle(), buf, 28, 100); + +// // Verify the sync and header bits +// if( buf[0] != 0xB5 || buf[1] != 0x62 ) +// led_set(LED_RED, 1); +// if( buf[2] != 0x01 || buf[3] != 0x21 ) +// led_set(LED_RED, 1); + + *hour = buf[22]; + *minute = buf[23]; + *second = buf[24]; + +// if( !_gps_verify_checksum(&buf[2], 24) ) led_set(LED_RED, 1); +} + +/** + * Check the navigation status to determine the quality of the + * fix currently held by the receiver with a NAV-STATUS message. + */ +void gps_check_lock(uint8_t* lock, uint8_t* sats) { - uint8_t sendctr; - for(sendctr = 0; sendctr < size; sendctr++) + // Construct the request to the GPS + uint8_t request[8] = {0xB5, 0x62, 0x01, 0x06, 0x00, 0x00, + 0x07, 0x16}; + HAL_UART_Transmit(uart_gethandle(), request, 8, 100); + + // Get the message back from the GPS + uint8_t buf[60]; + HAL_UART_Receive(uart_gethandle(), buf, 60, 100); + + // Verify the sync and header bits +// if( buf[0] != 0xB5 || buf[1] != 0x62 ) +// led_set(LED_RED, 1); +// if( buf[2] != 0x01 || buf[3] != 0x06 ) +// led_set(LED_RED, 1); + + // Check 60 bytes minus SYNC and CHECKSUM (4 bytes) +// if( !_gps_verify_checksum(&buf[2], 56) ) led_set(LED_RED, 1); + + // Return the value if GPSfixOK is set in 'flags' + if( buf[17] & 0x01 ) + *lock = buf[16]; + else + *lock = 0; + + *sats = buf[53]; +} + +/** + * Verify that the uBlox 6 GPS receiver is set to the <1g airborne + * navigaion mode. + */ +uint8_t gps_check_nav(void) +{ + uint8_t request[8] = {0xB5, 0x62, 0x06, 0x24, 0x00, 0x00, + 0x2A, 0x84}; + HAL_UART_Transmit(uart_gethandle(), request, 8, 100); + + // Get the message back from the GPS + uint8_t buf[44]; + HAL_UART_Receive(uart_gethandle(), buf, 44, 100); + +// // Verify sync and header bytes +// if( buf[0] != 0xB5 || buf[1] != 0x62 ) +// led_set(LED_RED, 1); +// if( buf[2] != 0x06 || buf[3] != 0x24 ) +// led_set(LED_RED, 1); + + // Check 40 bytes of message checksum +// if( !_gps_verify_checksum(&buf[2], 40) ) led_set(LED_RED, 1); + + // Clock in and verify the ACK/NACK + uint8_t ack[10]; + for(uint8_t i = 0; i < 10; i++) + ack[i] = _gps_get_byte(); + + // If we got a NACK, then return 0xFF + if( ack[3] == 0x00 ) return 0xFF; + + // Return the navigation mode and let the caller analyse it + return buf[8]; +} + +/** + * Verify the checksum for the given data and length. + */ + +static uint8_t _gps_verify_checksum(uint8_t* data, uint8_t len) +{ + uint8_t a, b; + gps_ubx_checksum(data, len, &a, &b); + if( a != *(data + len) || b != *(data + len + 1)) + return 0; + else + return 1; +} + +// Calculate a UBX checksum using 8-bit Fletcher (RFC1145) +static void gps_ubx_checksum(uint8_t* data, uint8_t len, uint8_t* cka, uint8_t* ckb) +{ + *cka = 0; + *ckb = 0; + for( uint8_t i = 0; i < len; i++ ) { - //usart_send(GPS_USART, dat[sendctr]); + *cka += *data; + *ckb += *cka; + data++; } } -// Could inline if program space available -static void setParserState(uint8_t state) -{ - decodeState = state; - // If resetting, clear vars - if(state == INITIALIZE) - { - calculatedChecksum = 0; - } - - // Every time we change state, we have parsed a byte - nmeaBufferParsePosition = (nmeaBufferParsePosition + 1) % NMEABUFFER_SIZE; +void gps_poweron(void) +{ + // NOTE: pchannel + HAL_GPIO_WritePin(GPS_NOTEN, 0); + uart_init(); + + // Begin DMA reception + //HAL_UART_Receive_DMA(uart_gethandle(), nmeaBuffer, NMEABUFFER_SIZE); } -static uint8_t gps_acquiring = 0; -static uint32_t gps_lastfix_time = 0; +void gps_poweroff(void) +{ + // NOTE: pchannel + uart_deinit(); + HAL_GPIO_WritePin(GPS_NOTEN, 1); +} + +// +//uint8_t gps_hadfix = 0; +//uint8_t gps_hasfix() +//{ +// uint8_t hasFix = get_latitudeTrimmed()[0] != 0x00; +// gps_hadfix = hasFix; +// return hasFix; +//} -void gps_process(void) -{ - // If we're trying to acquire a GPS fix - if(gps_acquiring) - { - // Process incoming bytes - parse_gps_transmission(); - - // If fix acquired - uint16_t hdop_int = get_hdop_int_tenths(); - if(hdop_int < 50 && hdop_int > 0) - { - // Set RTC to GPS time - - // Record time of fix (TODO: don't use ticks if sleeping... use RTC time) - gps_lastfix_time = HAL_GetTick(); +//void gps_sendubx(uint8_t* dat, uint8_t size) +//{ +// uint8_t sendctr; +// for(sendctr = 0; sendctr < size; sendctr++) +// { +// HAL_UART_Transmit(huart1, dat[sendctr]); +// } +//} - // Turn off GPS module - gps_poweroff(); - - // Invalidate HDOP - hdop[0] = '9'; - - // Go to idle state - gps_acquiring = 0; - } - else - { - // if too much time has elapsed, set an error flag and go idle - //gps_acquiring = 0; - } - } -} +uint8_t gps_acquiring= 0; +uint32_t gps_lastfix_time; void gps_acquirefix(void) { @@ -289,8 +262,6 @@ void gps_acquirefix(void) gps_acquiring = 1; } - - uint8_t gps_getstate(void) { if(gps_acquiring) @@ -304,477 +275,6 @@ uint8_t gps_getstate(void) } -// MKa GPS transmission parser START -void parse_gps_transmission(void) -{ - uint16_t nmeaBufferDataPosition = NMEABUFFER_SIZE - uart_get_rxdma_handle()->Instance->CNDTR; - - char byte; - - while(nmeaBufferDataPosition != nmeaBufferParsePosition) - { - // Pull byte off of the buffer - byte = nmeaBuffer[nmeaBufferParsePosition]; - - if(decodeState == INITIALIZE) //start of transmission sentence - { - if(byte == '$') - { - setParserState(GET_TYPE); - numBytes = 0; //prep for next phases - skipBytes = 0; - calculatedChecksum = 0; - } - - else - { - setParserState(INITIALIZE); - } - } - - //parse transmission type - else if (decodeState == GET_TYPE) - { - tramsmissionType[numBytes] = byte; - numBytes++; - - if(byte == ',') //end of this data type - { - tramsmissionType[5] = 0x00; - - if (tramsmissionType[2] == 'G' && - tramsmissionType[3] == 'G' && - tramsmissionType[4] == 'A') - { - setParserState(GGA_TIME); - numBytes = 0; - } - else if (tramsmissionType[2] == 'R' && - tramsmissionType[3] == 'M' && - tramsmissionType[4] == 'C') - { - setParserState(RMC_TIME); - numBytes = 0; - } - else //this is an invalid transmission type - { - setParserState(INITIALIZE); - } - } - else { - // continue - setParserState(GET_TYPE); - } - - } - - ///parses GGA transmissions START - /// $--GGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*xx - //timestamp - else if (decodeState == GGA_TIME) - { - if (byte == ',') //end of this data type - { - //timestamp[4] = 0x00; // Cut off at 4 (no seconds) for APRS - setParserState(GGA_LATITUDE); - skipBytes = 0; //prep for next phase of parse - numBytes = 0; - } - else //store data - { - setParserState(GGA_TIME); - timestamp[numBytes] = byte; //byte; //adjust number of bytes to fit array - numBytes++; - } - } - - //latitude - else if (decodeState == GGA_LATITUDE) - { - if (byte == ',' && skipBytes == 0) //discard this byte - { - skipBytes = 1; - setParserState(GGA_LATITUDE); - } - else if (byte == ',') //end of this data type - { - - latitude[numBytes] = 0x00; // null terminate - - setParserState(GGA_LONGITUDE); - skipBytes = 0; //prep for next phase of parse - numBytes = 0; - } - else //store data - { - latitude[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(GGA_LATITUDE); - } - } - - //longitude - else if (decodeState == GGA_LONGITUDE) - { - if (byte == ',' && skipBytes == 0) //discard this byte - { - skipBytes = 1; - setParserState(GGA_LONGITUDE); - } - else if (byte == ',') //end of this data type - { - longitude[numBytes] = 0x00; - setParserState(GGA_QUALITY); - numBytes = 0; //prep for next phase of parse - skipBytes = 0; - } - else //store data - { - longitude[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(GGA_LONGITUDE); - } - } - - //GGA quality - else if (decodeState == GGA_QUALITY) - { - if (byte == ',') //end of this data type - { - setParserState(GGA_SATELLITES); - numBytes = 0; //prep for next phase of parse - } - else //store data - { - quality = byte; //maybe reset if invalid data ?? - setParserState(GGA_QUALITY); - } - } - - //number of satellites - else if (decodeState == GGA_SATELLITES) - { - if (byte == ',') //end of this data type - { - numSatellites[numBytes] = 0x00; - setParserState(GGA_HDOP); - numBytes = 0; //prep for next phase of parse - } - else //store data - { - numSatellites[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(GGA_SATELLITES); - } - } - - //HDOP - else if (decodeState == GGA_HDOP) - { - if (byte == ',' ) //end of this data type - { - hdop[numBytes] = 0x00; - setParserState(GGA_ALTITUDE); - numBytes = 0; //prep for next phase of parse - skipBytes = 0; - } - else //store data - { - hdop[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(GGA_HDOP); - } - } - - //altitude - else if (decodeState == GGA_ALTITUDE) - { - if (byte == ',' && skipBytes == 0) //discard this byte - { - altitude[numBytes] = 0x00; - skipBytes = 1; - setParserState(GGA_ALTITUDE); - } - else if(byte == ',') //end of this data type - { - // If we actually have an altitude - if(numBytes>0) - { - altitude[numBytes-1] = 0x00; // Cut off the "M" from the end of the altitude - } - else - { - altitude[numBytes] = 0x00; - } - setParserState(GGA_WGS84); - numBytes = 0; //prep for next phase of parse - } - else //store data - { - altitude[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(GGA_ALTITUDE); - } - } - - //WGS84 Height - else if (decodeState == GGA_WGS84) - { - if (byte == ',' && skipBytes == 0) //discard this byte - { - skipBytes = 1; - setParserState(GGA_WGS84); - } - else if(byte == ',') //end of this data type - { - //wgs84Height[numBytes] = 0x00; - setParserState(GGA_LAST_UPDATE); - skipBytes = 0; //prep for next phase of parse - numBytes = 0; - } - else //store data - { - //wgs84Height[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(GGA_WGS84); - } - } - - //last GGA DGPS update - else if (decodeState == GGA_LAST_UPDATE) - { - if (byte == ',') //end of this data type - { -// lastUpdated[numBytes] = 0x00; - setParserState(GGA_STATION_ID); - numBytes = 0; //prep for next phase of parse - } - else //store data - this should be blank - { -// lastUpdated[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(GGA_LAST_UPDATE); - } - } - - //GGA DGPS station ID - else if (decodeState == GGA_STATION_ID) - { - if (byte == ',' || byte == '*') //end of this data type - { -// stationID[numBytes] = 0x00; - setParserState(GPS_CHECKSUM); - numBytes = 0; //prep for next phase of parse - } - else //store data - this should be blank - { -// stationID[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(GGA_STATION_ID); - } - } - ///parses GGA transmissions END - - /// $GPRMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,ddmmyy,x.x,a*hh - ///parses RMC transmissions - //time - // emz: commented setter, GMC time better? - else if(decodeState == RMC_TIME) - { - if (byte == ',') //end of this data type - { - //timestamp[numBytes] = 0x00; - setParserState(RMC_VALIDITY); - numBytes = 0; //prep for next phase of parse - } - else //store data - { - //timestamp[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - setParserState(RMC_TIME); - } - } - - //validity - // not needed? dupe gga - else if(decodeState == RMC_VALIDITY) - { - if (byte == ',') //end of this data type - { - setParserState(RMC_LATITUDE); - skipBytes = 0; //prep for next phase of parse - numBytes = 0; - } - else //store data - { - //quality = byte; - numBytes++; - setParserState(RMC_VALIDITY); - } - } - - //latitude RMC (we don't need this, commented out setter) - else if(decodeState == RMC_LATITUDE) - { - if (byte == ',' && skipBytes == 0) //discard this byte - { - skipBytes = 1; - setParserState(RMC_LATITUDE); - } - else if (byte == ',') //end of this data type - { - setParserState(RMC_LONGITUDE); - skipBytes = 0; //prep for next phase of parse - numBytes = 0; - } - else //store data - { - //latitude[numBytes]= byte; //adjust number of bytes to fit array - numBytes++; - setParserState(RMC_LATITUDE); - } - } - - //longitude RMC (we don't need this, commented out setter) - else if(decodeState == RMC_LONGITUDE) - { - if (byte == ',' && skipBytes == 0) //discard this byte - { - skipBytes = 1; - setParserState(RMC_LONGITUDE); - } - else if (byte == ',') //end of this data type - { - setParserState(RMC_KNOTS); - skipBytes = 0; - numBytes = 0; - } - else //store data - { - //longitude[numBytes]= byte; //adjust number of bytes to fit array - numBytes++; - setParserState(RMC_LONGITUDE); - } - } - - //knots - else if(decodeState == RMC_KNOTS) - { - if (byte == ',') //end of this data type - { - knots[numBytes] = 0x00; - setParserState(RMC_COURSE); - numBytes = 0; //prep for next phase of parse - } - else //store data - { - setParserState(RMC_KNOTS); - knots[numBytes]= byte; //adjust number of bytes to fit array - numBytes++; - } - } - - //course - else if(decodeState == RMC_COURSE) - { - if (byte == ',') //end of this data type - { - course[numBytes] = 0x00; - setParserState(RMC_DATE); - numBytes = 0; //prep for next phase of parse - } - else //store data - { - setParserState(RMC_COURSE); - course[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - } - } - - //date - else if(decodeState == RMC_DATE) - { - if (byte == ',') //end of this data type - { - // Cut it off at day of month. Also has month and year if we ever need it. - dayofmonth[2] = 0x00; - setParserState(RMC_MAG_VARIATION); - skipBytes = 0; //prep for next phase of parse - numBytes = 0; - } - else //store data - { - setParserState(RMC_DATE); - dayofmonth[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - } - } - - //magnetic variation - else if(decodeState == RMC_MAG_VARIATION) - { - if (byte == '*') //end of this data type - { - //variation[numBytes] = 0x00; - setParserState(GPS_CHECKSUM); - numBytes = 0; //prep for next phase of parse - } - else //store data - { - setParserState(RMC_MAG_VARIATION); - //variation[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - } - } - ///parses RMC transmissions END - - - //checksum - else if (decodeState == GPS_CHECKSUM) - { - if (numBytes == 2) //end of data - terminating character ?? - { - //checksum calculator for testing http://www.hhhh.org/wiml/proj/nmeaxor.html - //TODO: must determine what to do with correct and incorrect messages - receivedChecksum = checksum[0] + (checksum[1]*16); //convert bytes to int - if(calculatedChecksum==receivedChecksum) - { - - } - else - { - - } - - setParserState(INITIALIZE); - numBytes = 0; //prep for next phase of parse - } - else //store data - { - setParserState(GPS_CHECKSUM); - checksum[numBytes] = byte; //adjust number of bytes to fit array - numBytes++; - } - } - else { - setParserState(INITIALIZE); - } - - if (decodeState!=GPS_CHECKSUM && decodeState!=INITIALIZE) //want bytes between '$' and '*' - { - //input byte into running checksum - XORbyteWithChecksum(byte); - } - } - - -} - -void XORbyteWithChecksum(uint8_t byte) -{ - calculatedChecksum ^= (int)byte; //this may need to be re-coded -} - diff --git a/src/interrupts.c b/src/interrupts.c --- a/src/interrupts.c +++ b/src/interrupts.c @@ -5,7 +5,7 @@ #include "stm32f0xx_hal.h" #include "stm32f0xx.h" #include "interrupts.h" -#include "usart.h" +#include "uart.h" #include "gpio.h" extern TIM_HandleTypeDef htim1; diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -3,91 +3,13 @@ // #include "stm32f0xx_hal.h" -#include "si5351.h" -#include "jtencode.h" #include "adc.h" +#include "system.h" #include "i2c.h" -#include "usart.h" +#include "uart.h" #include "gpio.h" #include "gps.h" -#define WSPR_DEFAULT_FREQ 10140100UL -#define WSPR_TONE_SPACING 146 // ~1.46 Hz -#define WSPR_CTC 10672 // CTC value for WSPR - -// Private functions -void sysclk_init(void); -void enter_sleep(void); -void enter_deepsleep(void); - -// Test stuff -char call[7] = "KD8TDF"; -char loc[5] = "EN72"; -uint8_t dbm = 10; -uint8_t tx_buffer[255]; - -// Frequencies and channel info -uint32_t freq = WSPR_DEFAULT_FREQ; -uint8_t symbol_count = WSPR_SYMBOL_COUNT; -uint16_t ctc = WSPR_CTC; -uint16_t tone_spacing = WSPR_TONE_SPACING; -volatile uint8_t proceed = 0; - -// Bring up TCXO and oscillator IC -void encode_wspr(void) -{ - HAL_GPIO_WritePin(OSC_NOTEN, 0); - HAL_GPIO_WritePin(TCXO_EN, 1); - HAL_Delay(100); - - // Bring up the chip - si5351_init(i2c_get(), SI5351_CRYSTAL_LOAD_8PF, 0); - si5351_set_correction(0); - //si5351_set_pll(SI5351_PLL_FIXED, SI5351_PLLA); - //si5351_set_ms_source(SI5351_CLK0, SI5351_PLLA); - si5351_set_freq(WSPR_DEFAULT_FREQ * 100, 0, SI5351_CLK0); - si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); // Set for max power if desired (8ma max) - si5351_output_enable(SI5351_CLK0, 1); - //si5351_pll_reset(SI5351_PLLA); - - // Make sure the other outputs of the SI5351 are disabled - si5351_output_enable(SI5351_CLK1, 0); // Disable the clock initially - si5351_output_enable(SI5351_CLK2, 0); // Disable the clock initially - - // disable clock powers - si5351_set_clock_pwr(SI5351_CLK1, 0); - si5351_set_clock_pwr(SI5351_CLK2, 0); - - - // Encode message to transmit - wspr_encode(call, loc, dbm, tx_buffer); - - // Key transmitter - si5351_output_enable(SI5351_CLK0, 1); - - // Loop through and transmit symbols TODO: Do this from an ISR or ISR-triggered main loop function call (optimal) - uint8_t i; - for(i=0; i 10) { - gps_process(); + //gps_process(); last_gps = HAL_GetTick(); } @@ -193,58 +102,5 @@ int main(void) } -void enter_sleep(void) -{ - //HAL_SuspendTick(); - HAL_TIM_Base_Stop_IT(&htim1); - HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); - HAL_TIM_Base_Start_IT(&htim1); - //HAL_ResumeTick(); -} - - -void enter_deepsleep(void) -{ - // Request to enter STOP mode with regulator in low power mode - HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); - // After wake-up from STOP reconfigure the PLL - sysclk_init(); -} -// Initialize system clocks -void sysclk_init(void) -{ - RCC_OscInitTypeDef RCC_OscInitStruct; - RCC_ClkInitTypeDef RCC_ClkInitStruct; - RCC_PeriphCLKInitTypeDef PeriphClkInit; - - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI14; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.HSI14State = RCC_HSI14_ON; - RCC_OscInitStruct.HSICalibrationValue = 16; - RCC_OscInitStruct.HSI14CalibrationValue = 16; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; - HAL_RCC_OscConfig(&RCC_OscInitStruct); - - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK - |RCC_CLOCKTYPE_PCLK1; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; - HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); - - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1; - PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_SYSCLK; //RCC_USART1CLKSOURCE_PCLK1; - PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK; - HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); - - HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); - - HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); - - __SYSCFG_CLK_ENABLE(); - // SysTick_IRQn interrupt configuration - HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); -} - diff --git a/src/system.c b/src/system.c new file mode 100644 --- /dev/null +++ b/src/system.c @@ -0,0 +1,61 @@ +// +// System: basic low-level system configuration +// + +#include "stm32f0xx_hal.h" +#include "wspr.h" + +void enter_sleep(void) +{ + //HAL_SuspendTick(); + wspr_sleep(); + HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); + wspr_wakeup(); + //HAL_ResumeTick(); +} + + +void enter_deepsleep(void) +{ + // Request to enter STOP mode with regulator in low power mode + HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); + // After wake-up from STOP reconfigure the PLL + sysclk_init(); +} + + +// Initialize system clocks +void sysclk_init(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + RCC_PeriphCLKInitTypeDef PeriphClkInit; + + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSI14; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSI14State = RCC_HSI14_ON; + RCC_OscInitStruct.HSICalibrationValue = 16; + RCC_OscInitStruct.HSI14CalibrationValue = 16; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + HAL_RCC_OscConfig(&RCC_OscInitStruct); + + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); + + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1; + PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_SYSCLK; //RCC_USART1CLKSOURCE_PCLK1; + PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); + + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); + + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + + __SYSCFG_CLK_ENABLE(); + // SysTick_IRQn interrupt configuration + HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); +} diff --git a/src/usart.c b/src/uart.c rename from src/usart.c rename to src/uart.c --- a/src/usart.c +++ b/src/uart.c @@ -1,6 +1,6 @@ #include "stm32f0xx_hal.h" -#include "usart.h" +#include "uart.h" #include "config.h" #include "gpio.h" @@ -39,36 +39,36 @@ void uart_init(void) huart1.AdvancedInit.DMADisableonRxError = UART_ADVFEATURE_DMA_DISABLEONRXERROR; HAL_UART_Init(&huart1); - - __DMA1_CLK_ENABLE(); - - // Init UART DMA - hdma_usart1_rx.Instance = DMA1_Channel3; - hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; - hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; - hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; - hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; - HAL_DMA_Init(&hdma_usart1_rx); - - __HAL_LINKDMA(&huart1,hdmarx,hdma_usart1_rx); - - hdma_usart1_tx.Instance = DMA1_Channel2; - hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; - hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_usart1_tx.Init.MemInc = DMA_MINC_DISABLE; - hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_usart1_tx.Init.Mode = DMA_NORMAL; - hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; - HAL_DMA_Init(&hdma_usart1_tx); - - __HAL_LINKDMA(&huart1,hdmatx,hdma_usart1_tx); - -// HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0); -// HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); +// +// __DMA1_CLK_ENABLE(); +// +// // Init UART DMA +// hdma_usart1_rx.Instance = DMA1_Channel3; +// hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; +// hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; +// hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; +// hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; +// hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; +// hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; +// hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; +// HAL_DMA_Init(&hdma_usart1_rx); +// +// __HAL_LINKDMA(&huart1,hdmarx,hdma_usart1_rx); +// +// hdma_usart1_tx.Instance = DMA1_Channel2; +// hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; +// hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; +// hdma_usart1_tx.Init.MemInc = DMA_MINC_DISABLE; +// hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; +// hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; +// hdma_usart1_tx.Init.Mode = DMA_NORMAL; +// hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; +// HAL_DMA_Init(&hdma_usart1_tx); +// +// __HAL_LINKDMA(&huart1,hdmatx,hdma_usart1_tx); +// +//// HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0); +//// HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); //HAL_NVIC_EnableIRQ(USART1_IRQn); diff --git a/src/wspr.c b/src/wspr.c new file mode 100644 --- /dev/null +++ b/src/wspr.c @@ -0,0 +1,109 @@ +#include "stm32f0xx_hal.h" +#include "si5351.h" +#include "jtencode.h" +#include "gpio.h" +#include "wspr.h" +#include "config.h" + + +#define WSPR_DEFAULT_FREQ 10140100UL +#define WSPR_TONE_SPACING 146 // ~1.46 Hz +#define WSPR_CTC 10672 // CTC value for WSPR + +// Test stuff +char call[7] = "KD8TDF"; +char loc[5] = "EN72"; +uint8_t dbm = 10; +uint8_t tx_buffer[255]; + +// Frequencies and channel info +uint32_t freq = WSPR_DEFAULT_FREQ; +uint8_t symbol_count = WSPR_SYMBOL_COUNT; +uint16_t ctc = WSPR_CTC; +uint16_t tone_spacing = WSPR_TONE_SPACING; +volatile uint8_t proceed = 0; + +TIM_HandleTypeDef htim1; + + + +void wspr_init(void) +{ + // Start timer for WSPR + __TIM1_CLK_ENABLE(); + htim1.Instance = TIM1; + htim1.Init.Prescaler = 512; // gives 64uS ticks from 8MHz ahbclk + htim1.Init.CounterMode = TIM_COUNTERMODE_UP; + htim1.Init.Period = ctc; // Count up to this value (how many 64uS ticks per symbol) + htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim1.Init.RepetitionCounter = 0; + HAL_TIM_Base_Init(&htim1); + HAL_TIM_Base_Start_IT(&htim1); + HAL_NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); + +} + +// Do anything needed to prepare for sleep +void wspr_sleep(void) +{ + HAL_TIM_Base_Stop_IT(&htim1); +} + +void wspr_wakeup(void) +{ + HAL_TIM_Base_Start_IT(&htim1); +} + + +// Bring up TCXO and oscillator IC +void wspr_transmit(void) +{ + HAL_GPIO_WritePin(OSC_NOTEN, 0); + HAL_GPIO_WritePin(TCXO_EN, 1); + HAL_Delay(100); + + // Bring up the chip + si5351_init(i2c_get(), SI5351_CRYSTAL_LOAD_8PF, 0); + si5351_set_correction(0); + //si5351_set_pll(SI5351_PLL_FIXED, SI5351_PLLA); + //si5351_set_ms_source(SI5351_CLK0, SI5351_PLLA); + si5351_set_freq(WSPR_DEFAULT_FREQ * 100, 0, SI5351_CLK0); + si5351_drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); // Set for max power if desired (8ma max) + si5351_output_enable(SI5351_CLK0, 1); + //si5351_pll_reset(SI5351_PLLA); + + // Make sure the other outputs of the SI5351 are disabled + si5351_output_enable(SI5351_CLK1, 0); // Disable the clock initially + si5351_output_enable(SI5351_CLK2, 0); // Disable the clock initially + + // disable clock powers + si5351_set_clock_pwr(SI5351_CLK1, 0); + si5351_set_clock_pwr(SI5351_CLK2, 0); + + + // Encode message to transmit + wspr_encode(call, loc, dbm, tx_buffer); + + // Key transmitter + si5351_output_enable(SI5351_CLK0, 1); + + // Loop through and transmit symbols TODO: Do this from an ISR or ISR-triggered main loop function call (optimal) + uint8_t i; + for(i=0; i