📄 gps source code.txt
字号:
0xAE00, // ASCII = '.' 1010111
0xD780, // ASCII = '/' 110101111
0xB700, // ASCII = '0' 10110111
0xBD00, // ASCII = '1' 10111101
0xED00, // ASCII = '2' 11101101
0xFF00, // ASCII = '3' 11111111
0xBB80, // ASCII = '4' 101110111
0xAD80, // ASCII = '5' 101011011
0xB580, // ASCII = '6' 101101011
0xD680, // ASCII = '7' 110101101
0xD580, // ASCII = '8' 110101011
0xDB80, // ASCII = '9' 110110111
0xF500, // ASCII = ':' 11110101
0xDE80, // ASCII = ';' 110111101
0xF680, // ASCII = '<' 111101101
0xAA00, // ASCII = '=' 1010101
0xEB80, // ASCII = '>' 111010111
0xABC0, // ASCII = '?' 1010101111
0xAF40, // ASCII = '@' 1010111101
0xFA00, // ASCII = 'A' 1111101
0xEB00, // ASCII = 'B' 11101011
0xAD00, // ASCII = 'C' 10101101
0xB500, // ASCII = 'D' 10110101
0xEE00, // ASCII = 'E' 1110111
0xDB00, // ASCII = 'F' 11011011
0xFD00, // ASCII = 'G' 11111101
0xAA80, // ASCII = 'H' 101010101
0xFE00, // ASCII = 'I' 1111111
0xFE80, // ASCII = 'J' 111111101
0xBE80, // ASCII = 'K' 101111101
0xD700, // ASCII = 'L' 11010111
0xBB00, // ASCII = 'M' 10111011
0xDD00, // ASCII = 'N' 11011101
0xAB00, // ASCII = 'O' 10101011
0xD500, // ASCII = 'P' 11010101
0xEE80, // ASCII = 'Q' 111011101
0xAF00, // ASCII = 'R' 10101111
0xDE00, // ASCII = 'S' 1101111
0xDA00, // ASCII = 'T' 1101101
0xAB80, // ASCII = 'U' 101010111
0xDA80, // ASCII = 'V' 110110101
0xAE80, // ASCII = 'W' 101011101
0xBA80, // ASCII = 'X' 101110101
0xBD80, // ASCII = 'Y' 101111011
0xAB40, // ASCII = 'Z' 1010101101
0xFB80, // ASCII = '[' 1111101110
0xF780, // ASCII = '\' 111101111
0xFD80, // ASCII = ']' 111111011
0xAFC0, // ASCII = '^' 1010111111
0xB680, // ASCII = '_' 101101101
0xB7C0, // ASCII = '`' 1011011111
0xB000, // ASCII = 'a' 1011
0xBE00, // ASCII = 'b' 1011111
0xBC00, // ASCII = 'c' 101111
0xB400, // ASCII = 'd' 101101
0xC000, // ASCII = 'e' 11
0xF400, // ASCII = 'f' 111101
0xB600, // ASCII = 'g' 1011011
0xAC00, // ASCII = 'h' 101011
0xD000, // ASCII = 'i' 1101
0xF580, // ASCII = 'j' 111101011
0xBF00, // ASCII = 'k' 10111111
0xD800, // ASCII = 'l' 11011
0xEC00, // ASCII = 'm' 111011
0xF000, // ASCII = 'n' 1111
0xE000, // ASCII = 'o' 111
0xFC00, // ASCII = 'p' 111111
0xDF80, // ASCII = 'q' 110111111
0xA800, // ASCII = 'r' 10101
0xB800, // ASCII = 's' 10111
0xA000, // ASCII = 't' 101
0xDC00, // ASCII = 'u' 110111
0xF600, // ASCII = 'v' 1111011
0xD600, // ASCII = 'w' 1101011
0xDF00, // ASCII = 'x' 11011111
0xBA00, // ASCII = 'y' 1011101
0xEA80, // ASCII = 'z' 111010101
0xADC0, // ASCII = '{' 1010110111
0xDD80, // ASCII = '|' 110111011
0xAD40, // ASCII = '}' 1010110101
0xB5C0, // ASCII = '~' 1011010111
0xED40 // ASCII = 127 1110110101
};
// The maximum ASCII length of a PSK 31 message.
#define PSK_MAX_PACKET 160
// State machine constants.
#define PSK_WAIT_MSG 0
#define PSK_TX_SYNC 1
#define PSK_TX_MESSAGE 2
#define PSK_TX_END 3
// The UTC time in seconds to send a PSK31 data stream.
#define PSK31_TIMESLOT 0
// Number of 0 bits to transmit at start of message.
#define PSK_SYNC_LENGTH 32
// Number of 0 bits to transmit at end of message.
#define PSK_END_LENGTH 8
// PSK 31 frequency and amplitude list for time slots 0 through 2.
const uint32_t PSK31_FREQ_LIST[] = { 0x6C2FA66, 0x9615B57, 0xC1124BA };
const uint16_t PSK31_AMP_LIST[] = { 0x14ff, 0x14ff, 0x1300 };
// Counts the number of 1mS time slices in each 32mS of a bit time.
uint8_t pskCount;
// The current PSK output character.
uint16_t pskData;
// The current DDS phase offset where true is 180 degreees and false is 0 degrees.
boolean pskPhase;
// Buffer that holds PSK packet.
char pskBuffer[PSK_MAX_PACKET];
// State machine variable that indicates current transmit state.
uint8_t pskMode;
// Last 4 bits that were transmitted.
uint8_t pskLastBits;
// Index into the PSK packet buffer.
uint8_t pskIndex;
/**
*
* Create the PSK 31 packet.
*/
boolean psk31CreateDataPacket()
{
int16_t altitude;
uint16_t dop, speed, heading;
char *latitude, *longitude;
uint8_t utcHours, utcMinutes;
// Wait for the $GPRMC message and parse the speed/heading data from it.
if (!gpsWaitMessage (GPS_RMC_MSG))
return false;
speed = gpsParseSpeed();
heading = gpsParseHeading();
// Wait for the $GPGGA message and parse the rest of the data elements from it.
if (!gpsWaitMessage (GPS_GGA_MSG))
return false;
altitude = gpsParseAltitude();
latitude = gpsParseLatitude();
longitude = gpsParseLongitude();
dop = gpsParseDOP();
utcHours = gpsParseHours();
utcMinutes = gpsParseMinutes();
// Line 1 - Header
printf (psk31TxByte, "\n\n\nBalloon QSL www.kd7lmo.net\n");
// Line 2 - Data with units.
printf (psk31TxByte, "%02d%02dutc ", utcHours, utcMinutes);
if (altitude > 100)
printf (psk31TxByte, "%ld,", altitude / 100);
printf (psk31TxByte, "%02ld0ft ", altitude % 100);
psk31TxByte (gpsParseLatitudeOrdinal());
psk31TxString (latitude, 2);
psk31TxByte ('d');
psk31TxString (latitude + 2, 2);
psk31TxByte ('.');
psk31TxString (latitude + 5, 2);
printf (psk31TxByte, "m ");
psk31TxByte (gpsParseLongitudeOrdinal());
psk31TxString (longitude, 3);
psk31TxByte ('d');
psk31TxString (longitude + 3, 2);
psk31TxByte ('.');
psk31TxString (longitude + 6, 2);
printf (psk31TxByte, "m ");
printf (psk31TxByte, "%03ldmph@%03ldd ", speed, heading);
printf (psk31TxByte, "%ld.%lddop\n", dop / 10, dop % 10);
// Line 3 - Header / ident
printf (psk31TxByte, "QSL www.kd7lmo.net de AC7ZT\n");
// End of message line feeds.
printf (psk31TxByte, "\n\n");
// NULL terminate the string.
psk31TxNull();
return true;
}
/**
* Initialize the PSK 31 modulator.
*/
void psk31Init()
{
pskCount = 0;
pskData = 0x0000;
pskIndex = 0;
pskMode = PSK_WAIT_MSG;
pskPhase = false;
pskLastBits = 0x00;
}
/**
* Determine if the hardware if ready to a PSK 31 packet.
*
* @return true if ready; otherwise false
*/
boolean psk31IsFree()
{
if (pskMode == PSK_WAIT_MSG)
return true;
return false;
}
/**
* This method should be called every 1 milliseconds by the timer interrupt.
*/
void psk31TimeUpdate()
{
// If we are waiting for a message, just return.
if (pskMode == PSK_WAIT_MSG)
return;
// If our next bit is 0 (zero), ramp down the carrier.
if (pskCount == 15)
if ((pskData & 0x8000) == 0x0000)
output_low (IO_OSK);
// Every 32mS process the next bit.
if (++pskCount == 32) {
pskCount = 0;
switch (pskMode) {
case PSK_TX_SYNC:
// Just toggle the phase during the sync sequence.
if (pskPhase)
pskPhase = false;
else
pskPhase = true;
ddsPhase (pskPhase);
// After we send the start sequence, send the message.
if (--pskIndex == 0) {
pskMode = PSK_TX_MESSAGE;
pskIndex = 1;
pskData = PSK31_VARICODE[pskBuffer[0]];
pskLastBits = 0x0f;
} // END if
// Ramp the carrier back on.
output_high (IO_OSK);
break;
case PSK_TX_MESSAGE:
// Keep track of the last 4 bits we transmitted.
pskLastBits = (pskLastBits << 1) & 0x0f;
// If the data bit is a zero, toggle the phase.
if ((pskData & 0x8000) == 0x0000) {
if (pskPhase)
pskPhase = false;
else
pskPhase = true;
ddsPhase (pskPhase);
} else
pskLastBits |= 0x01;
// Shift to the next bit.
pskData = pskData << 1;
// If the last 2 bits we sent were 0, then get the next byte.
if ((pskLastBits & 0x0c) == 0x00)
// Stop when we find the NULL character.
if (pskBuffer[pskIndex] == 0) {
pskIndex = PSK_END_LENGTH;
pskMode = PSK_TX_END;
pskData = 0x0000;
} else {
// Get the next character in the buffer.
pskData = PSK31_VARICODE[pskBuffer[pskIndex++]];
// Reset the last bits shift register.
pskLastBits = 0x0f;
} // END if-else
output_high (IO_OSK);
break;
case PSK_TX_END:
// Just toggle the phase during the end sequence.
if (pskPhase)
pskPhase = false;
else
pskPhase = true;
ddsPhase (pskPhase);
if (--pskIndex == 0) {
// We are ready for a new mesasge.
pskMode = PSK_WAIT_MSG;
// Turn off the carrier.
output_low (IO_OSK);
// Turn off the PA.
sysPAOutput (false);
} else
output_high (IO_OSK);
break;
} // END switch
} // END if
}
/**
* Generate and start transmision of PSK-31 message. If a message is already
* being transmitted, nothing occurs. The UTC time in minutes is required to set
* the DDS frequency.
*
* @param minutes UTC time in minutes
*/
void psk31TxPacket(uint8_t minutes)
{
// We can't create a packet if one is already in progress.
if (pskMode != PSK_WAIT_MSG || !tncIsFree())
return;
// Set the pointer to the start of the buffer.
pskIndex = 0;
// If the packet generations fails, display a warning message.
if (!psk31CreateDataPacket()) {
pskIndex = 0;
printf (psk31TxByte, "Ballooon QSL www.kd7lmo.net * Unable to generate telemetry\n\n");
psk31TxNull();
}
// Select the PSK-31 real-time clock mode.
timeSetMode (TIME_MODE_PSK31);
// Configure the DDS for PSK-31 mode.
ddsSetMode (DDS_MODE_PSK31);
// Set the DDS frequency based on the time schedule that repeats every 6 minutes.
ddsSetFreq (PSK31_FREQ_LIST[minutes % 3]);
ddsSetAmplitude (PSK31_AMP_LIST[minutes % 3]);
// Turn on the PA.
sysPAOutput (true);
// Prepare the variables that are used in the real-time clock interrupt.
pskIndex = PSK_SYNC_LENGTH;
pskCount = 0;
pskData = 0x0000;
pskMode = PSK_TX_SYNC;
}
/**
* Write <b>value</b> to the PSK 31 buffer. Maintain the pointer
* to the buffer. The value pskIndex must be set to 0 (zero)
* before calling this function for the first time.
*
* @param value to save to telemetry buffer
*/
void psk31TxByte (uint8_t value)
{
if (pskIndex == PSK_MAX_PACKET)
return;
pskBuffer[pskIndex++] = value;
}
/**
* Write <b>length</b> characters of <b>string</b>.
*/
void psk31TxString (char *string, uint8_t length)
{
while (length-- != 0)
psk31TxByte (*string++);
}
void psk31TxNull ()
{
psk31TxByte (0x00);
}
// ****************************************************************************
// Serial port
//
// Note this size must be a power of 2, i.e. 2, 4, 8, 16, etc.
#define SERIAL_BUFFER_SIZE 64
// Mask to wrap around at end of circular buffer. (SERIAL_BUFFER_SIZE - 1)
#define SERIAL_BUFFER_MASK 0x3f
// Index to the next free location in the buffer.
uint8_t serialHead;
// Index to the next oldest data in the buffer.
uint8_t serialTail;
// Buffer to hold serial data.
uint8_t serialBuffer[SERIAL_BUFFER_SIZE];
/**
* Determine if the FIFO contains data.
*
* @return true if data present; otherwise false
*/
boolean serialHasData()
{
if (serialHead == serialTail)
return false;
return true;
}
/**
* Initialize the serial processor.
*/
void serialInit()
{
serialHead = 0;
serialTail = 0;
}
/**
* Get the oldest character from the FIFO.
*
* @return oldest character; 0 if FIFO is empty
*/
uint8_t serialRead()
{
uint8_t value;
// Make sure we have something to return.
if (serialHead == serialTail)
return 0;
// Save the value.
value = serialBuffer[serialTail];
// Update the pointer.
serialTail = (serialTail + 1) & SERIAL_BUFFER_MASK;
return value;
}
/**
* Read and store any characters in the PIC serial port in a FIFO.
*/
void serialUpdate()
{
// If there isn't a character in the PIC buffer, just leave.
while (kbhit()) {
// Save the value in the FIFO.
serialBuffer[serialHead] = getc();
// Move the pointer to the next open space.
serialHead = (serialHead + 1) & SERIAL_BUFFER_MASK;
}
}
// ****************************************************************************
// System methods
//
/**
* Calculate the CRC-16 CCITT of <b>buffer</b> that is <b>length</b> bytes long.
* The <b>crc</b> parameter allow the calculation on the CRC on multiple buffers.
*
* @param buffer Pointer to data buffer.
* @param length number of bytes in data buffer
* @param crc starting value
*
* @return CRC-16 of buffer[0 .. length]
*/
uint16_t sysCRC16(uint8_t *buffer, uint8_t length, uint16_t crc)
{
uint8_t i, bit, value;
for (i = 0; i < length; ++i) {
value = buffer[i];
for (bit = 0; bit < 8; ++bit) {
crc ^= (value & 0x01);
crc = ( crc & 0x01 ) ? ( crc >> 1 ) ^ 0x8408 : ( crc >> 1 );
value = value >> 1;
} // END for
} // END for
return crc ^ 0xffff;
}
/**
* Control the PA output.
*
* @param state true to turn on PA; otherwise false
*/
inline void sysPAOutput (boolean state)
{
if (state)
output_low (IO_PA);
else
output_high (IO_PA);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -