X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=src%2Fdrivers%2Fao_aprs.c;h=cea802bb9b9578e01736474503df82bc6ccfc7ff;hb=fe820a8a2dc6248b5edb96a9521536d41b936116;hp=79cea49afbaa87028986e39e03a694a69f81964f;hpb=024e35dc6a0356adfc801a023d5ec208cf3996cb;p=fw%2Faltos diff --git a/src/drivers/ao_aprs.c b/src/drivers/ao_aprs.c index 79cea49a..cea802bb 100644 --- a/src/drivers/ao_aprs.c +++ b/src/drivers/ao_aprs.c @@ -139,96 +139,21 @@ * */ -// Hardware specific configuration. -#include <18f2525.h> -#device ADC=10 +#ifndef AO_APRS_TEST +#include +#endif -// NOTE: Even though we are using an external clock, we set the HS oscillator mode to -// make the PIC 18F252 work with our external clock which is a clipped 1V P-P sine wave. -#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP +#include -// C runtime library definitions. -#include -#include - -// These compiler directives set the clock, SPI/I2C ports, and I/O configuration. - -// TCXO frequency -#use delay(clock=19200000) - -// Engineering and data extracation port. -#use rs232(baud=57600, xmit=PIN_B7, rcv=PIN_B6, STREAM=PC_HOST) - -// GPS engine -#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) - -#use i2c (master, scl=PIN_C3, sda=PIN_C4) - -#use fast_io(A) -#use fast_io(B) -#use fast_io(C) - -// We define types that are used for all variables. These are declared -// because each processor has a different sizes for int and long. -// The PIC compiler defines int8_t, int16_t, and int32_t. - -/// Boolean value { false, true } -typedef boolean bool_t; - -/// Signed 8-bit number in the range -128 through 127. -typedef signed int8 int8_t; - -/// Unsigned 8-bit number in the range 0 through 255. -typedef unsigned int8 uint8_t; - -/// Signed 16-bit number in the range -32768 through 32767. -typedef signed int16 int16_t; - -/// Unsigned 16-bit number in the range 0 through 65535. -typedef unsigned int16 uint16_t; - -/// Signed 32-bit number in the range -2147483648 through 2147483647. -typedef signed int32 int32_t; - -/// Unsigned 32-bit number in the range 0 through 4294967296. -typedef unsigned int32 uint32_t; - -// Function and structure prototypes. These are declared at the start of -// the file much like a C++ header file. - -// Map I/O pin names to hardware pins. - -/// Heartbeat LED - Port A2 -#define IO_LED PIN_A2 - -/// AD9954 DDS Profile Select 0 - Port A3 -#define IO_PS0 PIN_A3 - -/// UHF amplifier and PA chain - Port A4 -#define IO_PTT PIN_A4 - -/// AD9954 DDS Update - Port A5 -#define IO_UPDATE PIN_A5 - -/// AD9954 CS (Chip Select) - Port B0 -#define IO_CS PIN_B0 - -/// GPS Engine Power - Port B1 -#define IO_GPS_PWR PIN_B1 - -/// AD9954 DDS Profile Select 1 - Port C0 -#define IO_PS1 PIN_C0 - -/// AD9954 DDS OSK (Output Shift Key) - Port C2 -#define IO_OSK PIN_C2 - -/// GPS engine serial transmit pin - Port C6 -#define IO_GPS_TXD PIN_C6 +typedef int bool_t; +typedef int32_t int32; +#define false 0 +#define true 1 // Public methods, constants, and data structures for each class. /// Operational modes of the AD9954 DDS for the ddsSetMode function. -enum DDS_MODE +typedef enum { /// Device has not been initialized. DDS_MODE_NOT_INITIALIZED, @@ -241,7 +166,7 @@ enum DDS_MODE /// Generate true FSK tones. DDS_MODE_FSK -}; +} DDS_MODE; void ddsInit(); void ddsSetAmplitude (uint8_t amplitude); @@ -251,15 +176,8 @@ void ddsSetFreq (uint32_t freq); void ddsSetFTW (uint32_t ftw); void ddsSetMode (DDS_MODE mode); -void flashErase(); -uint8_t flashGetByte (); -void flashReadBlock(uint32_t address, uint8_t *block, uint16_t length); -void flashSendByte(uint8_t value); -void flashSendAddress(uint32_t address); -void flashWriteBlock(uint32_t address, uint8_t *block, uint8_t length); - /// Type of GPS fix. -enum GPS_FIX_TYPE +typedef enum { /// No GPS FIX GPS_NO_FIX, @@ -269,7 +187,7 @@ enum GPS_FIX_TYPE /// 3D (Latitude/Longitude/Altitude) fix. GPS_3D_FIX -}; +} GPS_FIX_TYPE; /// GPS Position information. typedef struct @@ -329,6 +247,8 @@ typedef struct uint8_t visibleSats; } GPSPOSITION_STRUCT; +GPSPOSITION_STRUCT gpsPosition; + void gpsInit(); bool_t gpsIsReady(); GPS_FIX_TYPE gpsGetFixType(); @@ -337,47 +257,7 @@ void gpsPowerOn(); bool_t gpsSetup(); void gpsUpdate(); -int16_t lm92GetTemp(); - -/// Define the log record types. -enum LOG_TYPE -{ - /// Time stamp the log was started. - LOG_BOOTED = 0xb4, - - /// GPS coordinates. - LOG_COORD = 0xa5, - - /// Temperature - LOG_TEMPERATURE = 0x96, - - /// Bus voltage. - LOG_VOLTAGE = 0x87 -}; - -void logInit(); -uint32_t logGetAddress(); -void logType (LOG_TYPE type); -void logUint8 (uint8_t value); -void logInt16 (int16_t value); - -bool_t serialHasData(); -void serialInit(); -uint8_t serialRead(); -void serialUpdate(); - uint16_t sysCRC16(uint8_t *buffer, uint8_t length, uint16_t crc); -void sysInit(); -void sysLogVoltage(); - -/// 0% duty cycle (LED Off) constant for function timeSetDutyCycle -#define TIME_DUTYCYCLE_0 0 - -/// 10% duty cycle constant for function timeSetDutyCycle -#define TIME_DUTYCYCLE_10 1 - -/// 70% duty cycle constant for function timeSetDutyCycle -#define TIME_DUTYCYCLE_70 7 uint8_t timeGetTicks(); void timeInit(); @@ -385,7 +265,7 @@ void timeSetDutyCycle (uint8_t dutyCycle); void timeUpdate(); /// Operational modes of the TNC for the tncSetMode function. -enum TNC_DATA_MODE +typedef enum { /// No operation waiting for setup and configuration. TNC_MODE_STANDBY, @@ -395,7 +275,7 @@ enum TNC_DATA_MODE /// 9600 bps using true FSK tones. TNC_MODE_9600_FSK -}; +} TNC_DATA_MODE; void tncInit(); bool_t tncIsFree(); @@ -406,395 +286,8 @@ void tnc9600TimerTick(); void tncTxByte (uint8_t value); void tncTxPacket(TNC_DATA_MODE dataMode); -/** - * @defgroup ADC Analog To Digital Converter - * - * Control and manage the on board PIC A/D converter. - * - * @{ - */ - -/// Filtered voltages using a single pole, low pass filter. -uint16_t adcMainBusVolt; - -/// PIC ADC Channel number of the reference voltage. -#define ADC_REF 0 - -/// PIC ADC Channel number of the main bus voltage. -#define ADC_MAINBUS 1 - -/// Input diode drop in units of 0.01 volts. -#define MAIN_BUS_VOLT_OFFSET 20 - -/** - * Intialize the ADC subsystem. - */ -void adcInit() -{ - // Setup the ADC. - setup_adc_ports(AN0_TO_AN1); - setup_adc( ADC_CLOCK_DIV_32 ); - - // Zero the ADC filters. - adcMainBusVolt = 0; -} - -/** - * Filtered main bus voltage in 10mV resolution. - * - * @return voltage in 10mV steps - */ -uint16_t adcGetMainBusVolt() -{ - uint32_t volts; - - volts = (uint32_t) (adcMainBusVolt >> 3); - - volts = (volts * 330l) / 1023l; - - return (uint16_t) volts + MAIN_BUS_VOLT_OFFSET; -} - -/** - * Get the current ADC value for the main bus voltage. - * - * @return ADC value in the range 0 to 1023 - */ -uint16_t adcRawBusVolt() -{ - set_adc_channel(ADC_MAINBUS); - delay_us(50); - return read_adc(); -} - -/** - * Get the current ADC value for the reference source voltage. - * - * @return ADC value in the range 0 to 1023 - */ -uint16_t adcRawRefVolt() -{ - set_adc_channel(ADC_REF); - delay_us(50); - return read_adc(); -} - -/** - * Read and filter the ADC channels for bus voltages. - */ -void adcUpdate(void) -{ - // Filter the bus voltage using a single pole low pass filter. - set_adc_channel(ADC_MAINBUS); - delay_us(50); - adcMainBusVolt = read_adc() + adcMainBusVolt - (adcMainBusVolt >> 3); -} - -/** @} */ - - -/** - * @defgroup diag Diagnostics and Control - * - * Functions for diagnostics and control of the hardware and flight data recorder. - * - * @{ - */ - -/// Number of bytes per line to display when reading flight data recorder. -#define DIAG_BYTES_PER_LINE 32 - -/** - * Process the command to erase the data logger flash. - */ -void diagEraseFlash() -{ - // Confirm we want to erase the flash with the key sequence 'yes' . - fprintf (PC_HOST, "Are you sure (yes)? "); - - if (fgetc(PC_HOST) != 'y') - return; - - if (fgetc(PC_HOST) != 'e') - return; - - if (fgetc(PC_HOST) != 's') - return; - - if (fgetc(PC_HOST) != 13) - return; - - // User feedback and erase the part. - fprintf (PC_HOST, "Erasing flash..."); - - flashErase(); - - fprintf (PC_HOST, "done.\n\r"); -} - -/** - * Display the engineering mode menu. - */ -void diagMenu() -{ - // User interface. - fprintf (PC_HOST, "Options: (e)rase Flash, (r)ead Flash\n\r"); - fprintf (PC_HOST, " Toggle (L)ED\n\r"); - fprintf (PC_HOST, " (P)TT - Push To Transmit\n\r"); - fprintf (PC_HOST, " (f)requencey down, (F)requency up - 1KHz step\n\r"); - fprintf (PC_HOST, " (c)hannel down, (C)hannel up - 25KHz step\n\r"); - fprintf (PC_HOST, " (a)mplitude down, (A)mplitude up - 0.5 dB steps\n\r"); - fprintf (PC_HOST, " e(x)it engineering mode\n\r"); -} - -/** - * Process the command to dump the contents of the data logger flash. - */ -void diagReadFlash() -{ - bool_t dataFoundFlag, userStopFlag; - uint8_t i, buffer[DIAG_BYTES_PER_LINE]; - uint32_t address; - - // Set the initial conditions to read the flash. - address = 0x0000; - userStopFlag = false; - - do - { - // Read each block from the flash device. - flashReadBlock (address, buffer, DIAG_BYTES_PER_LINE); - - // This flag will get set if any data byte is not equal to 0xff (erase flash state) - dataFoundFlag = false; - - // Display the address. - fprintf (PC_HOST, "%08lx ", address); - - // Display each byte in the line. - for (i = 0; i < DIAG_BYTES_PER_LINE; ++i) - { - fprintf (PC_HOST, "%02x", buffer[i]); - - // Set this flag if the cell is not erased. - if (buffer[i] != 0xff) - dataFoundFlag = true; - - // Any key will abort the transfer. - if (kbhit(PC_HOST)) - userStopFlag = true; - } // END for - - // at the end of each line. - fprintf (PC_HOST, "\n\r"); - - // Advance to the next block of memory. - address += DIAG_BYTES_PER_LINE; - } while (dataFoundFlag && !userStopFlag); - - // Feedback to let the user know why the transfer stopped. - if (userStopFlag) - fprintf (PC_HOST, "User aborted download!\n\r"); -} - -void diag1PPS() -{ - uint16_t timeStamp, lastTimeStamp; - - lastTimeStamp = 0x0000; - - gpsPowerOn(); - - for (;;) - { - timeStamp = CCP_2; - - if (timeStamp != lastTimeStamp) - { - delay_ms (10); - - timeStamp = CCP_2; - - fprintf (PC_HOST, "%lu %lu\n\r", timeStamp, (timeStamp - lastTimeStamp)); - - lastTimeStamp = timeStamp; - } - } -} - -/** - * Process diagnostic commands through the debug RS-232 port. - */ -void diagPort() -{ - bool_t diagDoneFlag, ledFlag, paFlag, showSettingsFlag; - uint8_t command, amplitude; - uint32_t freqHz; - - // If the input is low, we aren't connected to the RS-232 device so continue to boot. - if (!input(PIN_B6)) - return; - - fprintf (PC_HOST, "Engineering Mode\n\r"); - fprintf (PC_HOST, "Application Built %s %s\n\r", __DATE__, __TIME__); - - // Current state of the status LED. - ledFlag = false; - output_bit (IO_LED, ledFlag); - - // This flag indicates we are ready to leave the diagnostics mode. - diagDoneFlag = false; - - // Current state of the PA. - paFlag = false; - - // Flag that indicate we should show the current carrier frequency. - showSettingsFlag = false; - - // Set the initial carrier frequency and amplitude. - freqHz = 445950000; - amplitude = 0; - - // Wait for the exit command. - while (!diagDoneFlag) - { - // Wait for the user command. - command = fgetc(PC_HOST); - - // Decode and process the key stroke. - switch (command) - { - case 'e': - diagEraseFlash(); - logInit(); - break; - - case 'l': - case 'L': - ledFlag = (ledFlag ? false : true); - output_bit (IO_LED, ledFlag); - break; - - case 'h': - case 'H': - case '?': - diagMenu(); - break; - - case 'r': - diagReadFlash(); - break; - - case 't': - tncHighRate (true); - fprintf (PC_HOST, "Set high rate TNC.\n\r"); - break; - - case 'f': - freqHz -= 1000; - ddsSetFreq (freqHz); - - // Display the new frequency. - showSettingsFlag = true; - break; - - case 'F': - freqHz += 1000; - ddsSetFreq (freqHz); - - // Display the new frequency. - showSettingsFlag = true; - break; - - case 'c': - freqHz -= 25000; - ddsSetFreq (freqHz); - - // Display the new frequency. - showSettingsFlag = true; - break; - - case 'C': - freqHz += 25000; - ddsSetFreq (freqHz); - - // Display the new frequency. - showSettingsFlag = true; - break; - - case 'p': - case 'P': - ddsSetFreq (freqHz); - - paFlag = (paFlag ? false : true); - output_bit (IO_PTT, paFlag); - output_bit (IO_OSK, paFlag); - - if (paFlag) - { - ddsSetMode (DDS_MODE_AFSK); - ddsSetAmplitude (amplitude); - } else - ddsSetMode (DDS_MODE_POWERDOWN); - - break; - - case 'a': - if (amplitude != 200) - { - amplitude += 5; - ddsSetAmplitude (amplitude); - - // Display the new amplitude. - showSettingsFlag = true; - } - break; - - case 'A': - if (amplitude != 0) - { - amplitude -= 5; - ddsSetAmplitude (amplitude); - - // Display the new amplitude. - showSettingsFlag = true; - } - break; - - case 'g': - diag1PPS(); - break; - - case 'x': - diagDoneFlag = true; - break; - - default: - fprintf (PC_HOST, "Invalid command. (H)elp for menu.\n\r"); - break; - } // END switch - - // Display the results of any user requests or commands. - if (showSettingsFlag) - { - showSettingsFlag = false; - - fprintf (PC_HOST, "%03ld.%03ld MHz ", freqHz / 1000000, (freqHz / 1000) % 1000); - fprintf (PC_HOST, "%d.%01ddBc\n\r", amplitude / 10, amplitude % 10); - - } // END if - - } // END while - - // Let the user know we are done with this mode. - fprintf (PC_HOST, "Exit diagnostic mode.\n\r"); - - return; -} - /** @} */ - /** * @defgroup DDS AD9954 DDS (Direct Digital Synthesizer) * @@ -894,89 +387,6 @@ const uint32_t freqTable[256] = 955409113, 955410249, 955411390, 955412535, 955413684, 955414836, 955415989, 955417144 }; -/** - * Initialize the DDS regsiters and RAM. - */ -void ddsInit() -{ - // Setup the SPI port for the DDS interface. - setup_spi( SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H ); - - // Set the initial DDS mode. The ddsSetMode function uses this value to make the desired DDS selections. - ddsMode = DDS_MODE_NOT_INITIALIZED; - - // Set the DDS operational mode. - ddsSetMode (DDS_MODE_POWERDOWN); - - // Set the output to full scale. - ddsSetOutputScale (0x3fff); - - // CFR2 (Control Function Register No. 2) - output_low (IO_CS); - spi_write (DDS_AD9954_CFR2); - - spi_write (0x00); // Unused register bits - spi_write (0x00); - spi_write (0x9c); // 19x reference clock multipler, high VCO range, nominal charge pump current - output_high (IO_CS); - - // ARR (Amplitude Ramp Rate) to 15mS for OSK - output_low (IO_CS); - spi_write (DDS_AD9954_ARR); - - spi_write (83); - output_high (IO_CS); - - // Strobe the part so we apply the updates. - output_high (IO_UPDATE); - output_low (IO_UPDATE); -} - -/** - * Set DDS amplitude value in the range 0 to 16383 where 16383 is full scale. This value is a - * linear multiplier and needs to be scale for RF output power in log scale. - * - * @param scale in the range 0 to 16383 - */ -void ddsSetOutputScale (uint16_t scale) -{ - // Set ASF (Amplitude Scale Factor) - output_low (IO_CS); - spi_write (DDS_AD9954_ASF); - - spi_write ((scale >> 8) & 0xff); - spi_write (scale & 0xff); - - output_high (IO_CS); - - // Strobe the DDS to set the amplitude. - output_high (IO_UPDATE); - output_low (IO_UPDATE); -} - -/** - * Set the DDS amplitude in units of dBc of full scale where 1 is 0.1 dB. For example, a value of 30 is 3dBc - * or a value of 85 is 8.5dBc. - * - * @param amplitude in 0.1 dBc of full scale - */ -void ddsSetAmplitude (uint8_t amplitude) -{ - // Range limit based on the lookup table size. - if (amplitude > 200) - return; - - // Set the linear DDS ASF (Amplitude Scale Factor) based on the dB lookup table. - ddsSetOutputScale (DDS_AMP_TO_SCALE[amplitude / 5]); - - // Toggle the DDS output low and then high to force it to ramp to the new output level setting. - output_low (IO_OSK); - delay_ms(25); - - output_high (IO_OSK); - delay_ms(25); -} - /** * Set DDS frequency tuning word. The output frequency is equal to RefClock * (ftw / 2 ^ 32). * @@ -984,20 +394,8 @@ void ddsSetAmplitude (uint8_t amplitude) */ void ddsSetFTW (uint32_t ftw) { - // Set FTW0 (Frequency Tuning Word 0) - output_low (IO_CS); - spi_write (DDS_AD9954_FTW0); - - spi_write ((ftw >> 24) & 0xff); - spi_write ((ftw >> 16) & 0xff); - spi_write ((ftw >> 8) & 0xff); - spi_write (ftw & 0xff); - - output_high (IO_CS); - - // Strobe the DDS to set the frequency. - output_high (IO_UPDATE); - output_low (IO_UPDATE); + int x = ftw - freqTable[0]; + putchar (x > 0 ? 0xc0 : 0x40); } /** @@ -1029,31 +427,7 @@ void ddsSetFreq(uint32_t freq) */ void ddsSetFSKFreq (uint32_t ftw0, uint32_t ftw1) { - // Set FTW0 (Frequency Tuning Word 0) - output_low (IO_CS); - spi_write (DDS_AD9954_FTW0); - - spi_write ((ftw0 >> 24) & 0xff); - spi_write ((ftw0 >> 16) & 0xff); - spi_write ((ftw0 >> 8) & 0xff); - spi_write (ftw0 & 0xff); - - output_high (IO_CS); - - // Set FTW0 (Frequency Tuning Word 1) - output_low (IO_CS); - spi_write (DDS_AD9954_FTW1); - - spi_write ((ftw1 >> 24) & 0xff); - spi_write ((ftw1 >> 16) & 0xff); - spi_write ((ftw1 >> 8) & 0xff); - spi_write (ftw1 & 0xff); - - output_high (IO_CS); - - // Strobe the DDS to set the frequency. - output_high (IO_UPDATE); - output_low (IO_UPDATE); +// printf ("ftw0 %d ftw1 %d\n", ftw0, ftw1); } /** @@ -1063,342 +437,33 @@ void ddsSetFSKFreq (uint32_t ftw0, uint32_t ftw1) */ void ddsSetMode (DDS_MODE mode) { - // Save the current mode. - ddsMode = mode; - - switch (mode) - { - case DDS_MODE_POWERDOWN: - // CFR1 (Control Function Register No. 1) - output_low (IO_CS); - spi_write (DDS_AD9954_CFR1); - - spi_write (0x00); - spi_write (0x00); - spi_write (0x00); - spi_write (0xf0); // Power down all subsystems. - output_high (IO_CS); - break; - - case DDS_MODE_AFSK: - // CFR1 (Control Function Register No. 1) - output_low (IO_CS); - spi_write (DDS_AD9954_CFR1); - - spi_write (0x03); // OSK Enable and Auto OSK keying - spi_write (0x00); - spi_write (0x00); - spi_write (0x40); // Power down comparator circuit - output_high (IO_CS); - break; - - case DDS_MODE_FSK: - // CFR1 (Control Function Register No. 1) - output_low (IO_CS); - spi_write (DDS_AD9954_CFR1); - - spi_write (0x03); // Clear RAM Enable, OSK Enable, Auto OSK keying - spi_write (0x00); - spi_write (0x00); - spi_write (0x40); // Power down comparator circuit - output_high (IO_CS); - - // NOTE: The sweep rate requires 1/4 of a bit time (26uS) to transition. - // 6KHz delta = 70641 counts = (6KHz / 364.8MHz) * 2 ^ 32 - // SYNC_CLK = 91.2MHz 1/91.2MHz * 70641 * 1/29 = 26.7uS - - // NLSCW (Negative Linear Sweep Control Word) - output_low (IO_CS); - spi_write (DDS_AD9954_NLSCW); - - spi_write (1); // Falling sweep ramp rate word - spi_write (0x00); // Delta frequency tuning word - spi_write (0x00); - spi_write (0x00); - spi_write (250); - output_high (IO_CS); - - // PLSCW (Positive Linear Sweep Control Word) - output_low (IO_CS); - spi_write (DDS_AD9954_PLSCW); - - spi_write (1); // Rising sweep ramp rate word - spi_write (0x00); // Delta frequency tuning word - spi_write (0x00); - spi_write (0x00); - spi_write (250); - output_high (IO_CS); - break; - } // END switch - - // Strobe the DDS to change the mode. - output_high (IO_UPDATE); - output_low (IO_UPDATE); +// printf ("mode %d\n", mode); } /** @} */ /** - * @defgroup flash Flash Manager + * @defgroup GPS Motorola M12+ GPS Engine * - * Functions to control the ST MP25P80 serial flash device. + * Functions to control the Motorola M12+ GPS engine in native binary protocol mode. * * @{ */ -/// Flash Chip Select - Port B3 -#define FLASH_CS PIN_B3 - -/// Flash Clock - Port B5 -#define FLASH_CLK PIN_B5 - -/// Flash Data Input - Port B4 -#define FLASH_D PIN_B4 - -/// Flash Data Output - Port B2 -#define FLASH_Q PIN_B2 +/// The maximum length of a binary GPS engine message. +#define GPS_BUFFER_SIZE 50 -/** - * Determine if a flash write or erase operation is currently in progress. - * - * @return true if write/erase in progress - */ -bool_t flashIsWriteInProgress() +/// GPS parse engine state machine values. +typedef enum { - uint8_t status; - - output_low (FLASH_CS); + /// 1st start character '@' + GPS_START1, - // Read Status Register (RDSR) flash command. - flashSendByte (0x05); + /// 2nd start character '@' + GPS_START2, - status = flashGetByte(); - - output_high (FLASH_CS); - - return (((status & 0x01) == 0x01) ? true : false); -} - -/** - * Read a block of memory from the flash device. - * - * @param address of desired location in the range 0x00000 to 0xFFFFF (1MB) - * @param block pointer to locate of data block - * @param length number of bytes to read - */ -void flashReadBlock(uint32_t address, uint8_t *block, uint16_t length) -{ - uint16_t i; - - output_low (FLASH_CS); - - // Read Data Byte(s) (READ) flash command. - flashSendByte (0x03); - flashSendAddress (address); - - for (i = 0; i < length; ++i) - *block++ = flashGetByte(); - - output_high (FLASH_CS); -} - -/** - * Write a block of memory to the flash device. - * - * @param address of desired location in the range 0x00000 to 0xFFFFF (1MB) - * @param block pointer data block to write - * @param length number of bytes to write - */ -void flashWriteBlock(uint32_t address, uint8_t *block, uint8_t length) -{ - uint8_t i; - - output_low (FLASH_CS); - // Write Enable (WREN) flash command. - flashSendByte (0x06); - output_high (FLASH_CS); - - output_low (FLASH_CS); - // Page Program (PP) flash command. - flashSendByte (0x02); - flashSendAddress (address); - - for (i = 0; i < length; ++i) - { - // Send each byte in the data block. - flashSendByte (*block++); - - // Track the address in the flash device. - ++address; - - // If we cross a page boundary (a page is 256 bytes) we need to stop and send the address again. - if ((address & 0xff) == 0x00) - { - output_high (FLASH_CS); - - // Write this block of data. - while (flashIsWriteInProgress()); - - output_low (FLASH_CS); - // Write Enable (WREN) flash command. - flashSendByte (0x06); - output_high (FLASH_CS); - - output_low (FLASH_CS); - // Page Program (PP) flash command. - flashSendByte (0x02); - flashSendAddress (address); - } // END if - } // END for - - output_high (FLASH_CS); - - // Wait for the final write operation to complete. - while (flashIsWriteInProgress()); -} - -/** - * Erase the entire flash device (all locations set to 0xff). - */ -void flashErase() -{ - output_low (FLASH_CS); - // Write Enable (WREN) flash command. - flashSendByte (0x06); - output_high (FLASH_CS); - - output_low (FLASH_CS); - // Bulk Erase (BE) flash command. - flashSendByte (0xc7); - output_high (FLASH_CS); - - while (flashIsWriteInProgress()); -} - -/** - * Read a single byte from the flash device through the serial interface. This function - * only controls the clock line. The chip select must be configured before calling - * this function. - * - * @return byte read from device - */ -uint8_t flashGetByte() -{ - uint8_t i, value; - - value = 0; - - // Bit bang the 8-bits. - for (i = 0; i < 8; ++i) - { - // Data is ready on the rising edge of the clock. - output_high (FLASH_CLK); - - // MSB is first, so shift left. - value = value << 1; - - if (input (FLASH_Q)) - value = value | 0x01; - - output_low (FLASH_CLK); - } // END for - - return value; -} - -/** - * Initialize the flash memory subsystem. - */ -void flashInit() -{ - // I/O lines to control flash. - output_high (FLASH_CS); - output_low (FLASH_CLK); - output_low (FLASH_D); -} - -/** - * Write a single byte to the flash device through the serial interface. This function - * only controls the clock line. The chip select must be configured before calling - * this function. - * - * @param value byte to write to device - */ -void flashSendByte(uint8_t value) -{ - uint8_t i; - - // Bit bang the 8-bits. - for (i = 0; i < 8; ++i) - { - // Drive the data input pin. - if ((value & 0x80) == 0x80) - output_high (FLASH_D); - else - output_low (FLASH_D); - - // MSB is first, so shift leeft. - value = value << 1; - - // Data is accepted on the rising edge of the clock. - output_high (FLASH_CLK); - output_low (FLASH_CLK); - } // END for -} - -/** - * Write the 24-bit address to the flash device through the serial interface. This function - * only controls the clock line. The chip select must be configured before calling - * this function. - * - * @param address 24-bit flash device address - */ -void flashSendAddress(uint32_t address) -{ - uint8_t i; - - // Bit bang the 24-bits. - for (i = 0; i < 24; ++i) - { - // Drive the data input pin. - if ((address & 0x800000) == 0x800000) - output_high (FLASH_D); - else - output_low (FLASH_D); - - // MSB is first, so shift left. - address = address << 1; - - // Data is accepted on the rising edge of the clock. - output_high (FLASH_CLK); - output_low (FLASH_CLK); - } // END for -} - -/** @} */ - -/** - * @defgroup GPS Motorola M12+ GPS Engine - * - * Functions to control the Motorola M12+ GPS engine in native binary protocol mode. - * - * @{ - */ - -/// The maximum length of a binary GPS engine message. -#define GPS_BUFFER_SIZE 50 - -/// GPS parse engine state machine values. -enum GPS_PARSE_STATE_MACHINE -{ - /// 1st start character '@' - GPS_START1, - - /// 2nd start character '@' - GPS_START2, - - /// Upper case 'A' - 'Z' message type - GPS_COMMAND1, + /// Upper case 'A' - 'Z' message type + GPS_COMMAND1, /// Lower case 'a' - 'z' message type GPS_COMMAND2, @@ -1414,7 +479,7 @@ enum GPS_PARSE_STATE_MACHINE /// End of message - Line Feed GPS_EOMLF -}; +} GPS_PARSE_STATE_MACHINE; /// Index into gpsBuffer used to store message data. uint8_t gpsIndex; @@ -1448,556 +513,172 @@ GPS_FIX_TYPE gpsGetFixType() return GPS_3D_FIX; case 0xc000: - return GPS_2D_FIX; - - default: - return GPS_NO_FIX; - } // END switch -} - -/** - * Peak altitude detected while GPS is in 3D fix mode since the system was booted. - * - * @return altitude in feet - */ -int32_t gpsGetPeakAltitude() -{ - return gpsPeakAltitude; -} - -/** - * Initialize the GPS subsystem. - */ -void gpsInit() -{ - // Initial parse state. - gpsParseState = GPS_START1; - - // Assume we start at sea level. - gpsPeakAltitude = 0; - - // Clear the structure that stores the position message. - memset (&gpsPosition, 0, sizeof(GPSPOSITION_STRUCT)); - - // Setup the timers used to measure the 1-PPS time period. - setup_timer_3(T3_INTERNAL | T3_DIV_BY_1); - setup_ccp2 (CCP_CAPTURE_RE | CCP_USE_TIMER3); -} - -/** - * Determine if new GPS message is ready to process. This function is a one shot and - * typically returns true once a second for each GPS position fix. - * - * @return true if new message available; otherwise false - */ -bool_t gpsIsReady() -{ - if (gpsPosition.updateFlag) - { - gpsPosition.updateFlag = false; - return true; - } // END if - - return false; -} - -/** - * Calculate NMEA-0183 message checksum of buffer that is length bytes long. - * - * @param buffer pointer to data buffer. - * @param length number of bytes in buffer. - * - * @return checksum of buffer - */ -uint8_t gpsNMEAChecksum (uint8_t *buffer, uint8_t length) -{ - uint8_t i, checksum; - - checksum = 0; - - for (i = 0; i < length; ++i) - checksum ^= buffer[i]; - - return checksum; -} - -/** - * Verify the GPS engine is sending the @@Hb position report message. If not, - * configure the GPS engine to send the desired report. - * - * @return true if GPS engine operation; otherwise false - */ -bool_t gpsSetup() -{ - uint8_t startTime, retryCount; - - // We wait 10 seconds for the GPS engine to respond to our message request. - startTime = timeGetTicks(); - retryCount = 0; - - while (++retryCount < 10) - { - // Read the serial FIFO and process the GPS messages. - gpsUpdate(); - - // If a GPS data set is available, then GPS is operational. - if (gpsIsReady()) - { - timeSetDutyCycle (TIME_DUTYCYCLE_10); - return true; - } - - if (timeGetTicks() > startTime) - { - puts ("@@Hb\001\053\015\012"); - startTime += 10; - } // END if - - } // END while - - return false; -} - -/** - * Parse the Motorola @@Hb (Short position/message) report. - */ -void gpsParsePositionMessage() -{ - // Convert the binary stream into data elements. We will scale to the desired units - // as the values are used. - gpsPosition.updateFlag = true; - - gpsPosition.month = gpsBuffer[0]; - gpsPosition.day = gpsBuffer[1]; - gpsPosition.year = ((uint16_t) gpsBuffer[2] << 8) | gpsBuffer[3]; - gpsPosition.hours = gpsBuffer[4]; - gpsPosition.minutes = gpsBuffer[5]; - gpsPosition.seconds = gpsBuffer[6]; - gpsPosition.latitude = ((int32) gpsBuffer[11] << 24) | ((int32) gpsBuffer[12] << 16) | ((int32) gpsBuffer[13] << 8) | (int32) gpsBuffer[14]; - gpsPosition.longitude = ((int32) gpsBuffer[15] << 24) | ((int32) gpsBuffer[16] << 16) | ((int32) gpsBuffer[17] << 8) | gpsBuffer[18]; - gpsPosition.altitudeCM = ((int32) gpsBuffer[19] << 24) | ((int32) gpsBuffer[20] << 16) | ((int32) gpsBuffer[21] << 8) | gpsBuffer[22]; - gpsPosition.altitudeFeet = gpsPosition.altitudeCM * 100l / 3048l; - gpsPosition.vSpeed = ((uint16_t) gpsBuffer[27] << 8) | gpsBuffer[28]; - gpsPosition.hSpeed = ((uint16_t) gpsBuffer[29] << 8) | gpsBuffer[30]; - gpsPosition.heading = ((uint16_t) gpsBuffer[31] << 8) | gpsBuffer[32]; - gpsPosition.dop = ((uint16_t) gpsBuffer[33] << 8) | gpsBuffer[34]; - gpsPosition.visibleSats = gpsBuffer[35]; - gpsPosition.trackedSats = gpsBuffer[36]; - gpsPosition.status = ((uint16_t) gpsBuffer[37] << 8) | gpsBuffer[38]; - - // Update the peak altitude if we have a valid 3D fix. - if (gpsGetFixType() == GPS_3D_FIX) - if (gpsPosition.altitudeFeet > gpsPeakAltitude) - gpsPeakAltitude = gpsPosition.altitudeFeet; -} - -/** - * Turn on the GPS engine power and serial interface. - */ -void gpsPowerOn() -{ - // 3.0 VDC LDO control line. - output_high (IO_GPS_PWR); - - // Enable the UART and the transmit line. -#asm - bsf 0xFAB.7 -#endasm -} - -/** - * Turn off the GPS engine power and serial interface. - */ -void gpsPowerOff() -{ - // Disable the UART and the transmit line. -#asm - bcf 0xFAB.7 -#endasm - - // 3.0 VDC LDO control line. - output_low (IO_GPS_PWR); -} - -/** - * Read the serial FIFO and process complete GPS messages. - */ -void gpsUpdate() -{ - uint8_t value; - - // This state machine handles each characters as it is read from the GPS serial port. - // We are looking for the GPS mesage @@Hb ... C - while (serialHasData()) - { - // Get the character value. - value = serialRead(); - - // Process based on the state machine. - switch (gpsParseState) - { - case GPS_START1: - if (value == '@') - gpsParseState = GPS_START2; - break; - - case GPS_START2: - if (value == '@') - gpsParseState = GPS_COMMAND1; - else - gpsParseState = GPS_START1; - break; - - case GPS_COMMAND1: - if (value == 'H') - gpsParseState = GPS_COMMAND2; - else - gpsParseState = GPS_START1; - break; - - case GPS_COMMAND2: - if (value == 'b') - { - gpsParseState = GPS_READMESSAGE; - gpsIndex = 0; - gpsChecksum = 0; - gpsChecksum ^= 'H'; - gpsChecksum ^= 'b'; - } else - gpsParseState = GPS_START1; - break; - - case GPS_READMESSAGE: - gpsChecksum ^= value; - gpsBuffer[gpsIndex++] = value; - - if (gpsIndex == 47) - gpsParseState = GPS_CHECKSUMMESSAGE; - - break; - - case GPS_CHECKSUMMESSAGE: - if (gpsChecksum == value) - gpsParseState = GPS_EOMCR; - else - gpsParseState = GPS_START1; - break; - - case GPS_EOMCR: - if (value == 13) - gpsParseState = GPS_EOMLF; - else - gpsParseState = GPS_START1; - break; - - case GPS_EOMLF: - // Once we have the last character, convert the binary message to something usable. - if (value == 10) - gpsParsePositionMessage(); - - gpsParseState = GPS_START1; - break; - } // END switch - } // END while -} - -/** @} */ - - -/** - * @defgroup log Flight Data Recorder - * - * Functions to manage and control the flight data recorder - * - * @{ - */ - -/// Number of bytes to buffer before writing to flash memory. -#define LOG_WRITE_BUFFER_SIZE 40 - -/// Last used address in flash memory. -uint32_t logAddress; - -/// Temporary buffer that holds data before it is written to flash device. -uint8_t logBuffer[LOG_WRITE_BUFFER_SIZE]; - -/// Current index into log buffer. -uint8_t logIndex; - -/** - * Last used address in flash memory. This location is where the next log data will - * be written. - * - * @return 24-bit flash memory address - */ -uint32_t logGetAddress() -{ - return logAddress; -} - -/** - * Write the contents of the temporary log buffer to the flash device. If the buffer - * is empty, nothing is done. - */ -void logFlush() -{ - // We only need to write if there is data. - if (logIndex != 0) - { - flashWriteBlock (logAddress, logBuffer, logIndex); - logAddress += logIndex; - logIndex = 0; - } // END if -} - -/** - * Prepare the flight data recorder for logging. - */ -void logInit() -{ - uint8_t buffer[8]; - bool_t endFound; - - fprintf (PC_HOST, "Searching for end of flash log..."); - - logAddress = 0x0000; - endFound = false; - - // Read each logged data block from flash to determine how long it is. - do - { - // Read the data log entry type. - flashReadBlock (logAddress, buffer, 1); - - // Based on the log entry type, we'll skip over the data contained in the entry. - switch (buffer[0]) - { - case LOG_BOOTED: - logAddress += 7; - break; - - case LOG_COORD: - logAddress += 26; - break; - - case LOG_TEMPERATURE: - logAddress += 3; - break; - - case LOG_VOLTAGE: - logAddress += 5; - break; - - case 0xff: - endFound = true; - break; - - default: - ++logAddress; - } // END switch - } while (logAddress < 0x100000 && !endFound); - - fprintf (PC_HOST, "done. Log contains %ld bytes.\n\r", logAddress); - - logIndex = 0; -} - -/** - * Start a entry in the data log. - * - * @param type of log entry, i.e. LOG_BOOTED, LOG_COORD, etc. - */ -void logType (LOG_TYPE type) -{ - // Only add the new entry if there is space. - if (logAddress >= 0x100000) - return; - - // Write the old entry first. - logFlush(); - - // Save the type and set the log buffer pointer. - logBuffer[0] = type; - logIndex = 1; + return GPS_2D_FIX; + + default: + return GPS_NO_FIX; + } // END switch } /** - * Save an unsigned, 8-bit value in the log. + * Peak altitude detected while GPS is in 3D fix mode since the system was booted. * - * @param value unsigned, 8-bit value + * @return altitude in feet */ -void logUint8 (uint8_t value) +int32_t gpsGetPeakAltitude() { - logBuffer[logIndex++] = value; + return gpsPeakAltitude; } -/** - * Save a signed, 16-bit value in the log. - * - * @param value signed, 16-bit value +/** + * Initialize the GPS subsystem. */ -void logInt16 (int16_t value) +void gpsInit() { - logBuffer[logIndex++] = (value >> 8) & 0xff; - logBuffer[logIndex++] = value & 0xff; -} + // Initial parse state. + gpsParseState = GPS_START1; -/** - * Save an unsigned, 16-bit value in the log. - * - * @param value unsigned, 16-bit value - */ -void logUint16 (uint16_t value) -{ - logBuffer[logIndex++] = (value >> 8) & 0xff; - logBuffer[logIndex++] = value & 0xff; + // Assume we start at sea level. + gpsPeakAltitude = 0; + + // Clear the structure that stores the position message. + memset (&gpsPosition, 0, sizeof(GPSPOSITION_STRUCT)); + + // Setup the timers used to measure the 1-PPS time period. +// setup_timer_3(T3_INTERNAL | T3_DIV_BY_1); +// setup_ccp2 (CCP_CAPTURE_RE | CCP_USE_TIMER3); } /** - * Save a signed, 32-bit value in the log. + * Determine if new GPS message is ready to process. This function is a one shot and + * typically returns true once a second for each GPS position fix. * - * @param value signed, 32-bit value + * @return true if new message available; otherwise false */ -void logInt32 (int32_t value) +bool_t gpsIsReady() { - logBuffer[logIndex++] = (value >> 24) & 0xff; - logBuffer[logIndex++] = (value >> 16) & 0xff; - logBuffer[logIndex++] = (value >> 8) & 0xff; - logBuffer[logIndex++] = value & 0xff; -} + return true; + if (gpsPosition.updateFlag) + { + gpsPosition.updateFlag = false; + return true; + } // END if -/** @} */ + return false; +} /** - * @defgroup LM92 LM92 temperature sensor - * - * Read and control the National Semiconductor LM92 I2C temperature sensor + * Calculate NMEA-0183 message checksum of buffer that is length bytes long. * - * @{ - */ - -/** - * Read the LM92 temperature value in 0.1 degrees F. + * @param buffer pointer to data buffer. + * @param length number of bytes in buffer. * - * @return 0.1 degrees F + * @return checksum of buffer */ -int16_t lm92GetTemp() +uint8_t gpsNMEAChecksum (uint8_t *buffer, uint8_t length) { - int16_t value; - int32_t temp; - - // Set the SDA and SCL to input pins to control the LM92. - set_tris_c (0x9a); - - // Read the temperature register value. - i2c_start(); - i2c_write(0x97); - value = ((int16_t) i2c_read() << 8); - value = value | ((int16_t) i2c_read() & 0x00f8); - i2c_stop(); + uint8_t i, checksum; - // Set the SDA and SCL back to outputs for use with the AD9954 because we share common clock pins. - set_tris_c (0x82); + checksum = 0; - // LM92 register 0.0625degC/bit 9 10 9 - // ------------- * -------------- * - * -- = -- + 320 - // 8 5 64 + for (i = 0; i < length; ++i) + checksum ^= buffer[i]; - // Convert to degrees F. - temp = (int32_t) value; - temp = ((temp * 9l) / 64l) + 320; - - return (int16_t) temp; + return checksum; } -/** @} */ - - /** - * @defgroup serial Serial Port FIFO - * - * FIFO for the built-in serial port. + * Verify the GPS engine is sending the @@Hb position report message. If not, + * configure the GPS engine to send the desired report. * - * @{ + * @return true if GPS engine operation; otherwise false */ +bool_t gpsSetup() +{ + uint8_t startTime, retryCount; -/// Size of serial port FIFO in bytes. It must be a power of 2, i.e. 2, 4, 8, 16, etc. -#define SERIAL_BUFFER_SIZE 64 + // We wait 10 seconds for the GPS engine to respond to our message request. + startTime = timeGetTicks(); + retryCount = 0; -/// Mask to wrap around at end of circular buffer. (SERIAL_BUFFER_SIZE - 1) -#define SERIAL_BUFFER_MASK 0x3f + while (++retryCount < 10) + { + // Read the serial FIFO and process the GPS messages. +// gpsUpdate(); -/// Index to the next free location in the buffer. -uint8_t serialHead; + // If a GPS data set is available, then GPS is operational. + if (gpsIsReady()) + { +// timeSetDutyCycle (TIME_DUTYCYCLE_10); + return true; + } -/// Index to the next oldest data in the buffer. -uint8_t serialTail; + if (timeGetTicks() > startTime) + { + puts ("@@Hb\001\053\015\012"); + startTime += 10; + } // END if + + } // END while -/// Circular buffer (FIFO) to hold serial data. -uint8_t serialBuffer[SERIAL_BUFFER_SIZE]; + return false; +} /** - * Determine if the FIFO contains data. - * - * @return true if data present; otherwise false + * Parse the Motorola @@Hb (Short position/message) report. */ -bool_t serialHasData() +void gpsParsePositionMessage() { - if (serialHead == serialTail) - return false; + // Convert the binary stream into data elements. We will scale to the desired units + // as the values are used. + gpsPosition.updateFlag = true; - return true; -} + gpsPosition.month = gpsBuffer[0]; + gpsPosition.day = gpsBuffer[1]; + gpsPosition.year = ((uint16_t) gpsBuffer[2] << 8) | gpsBuffer[3]; + gpsPosition.hours = gpsBuffer[4]; + gpsPosition.minutes = gpsBuffer[5]; + gpsPosition.seconds = gpsBuffer[6]; + gpsPosition.latitude = ((int32) gpsBuffer[11] << 24) | ((int32) gpsBuffer[12] << 16) | ((int32) gpsBuffer[13] << 8) | (int32) gpsBuffer[14]; + gpsPosition.longitude = ((int32) gpsBuffer[15] << 24) | ((int32) gpsBuffer[16] << 16) | ((int32) gpsBuffer[17] << 8) | gpsBuffer[18]; + gpsPosition.altitudeCM = ((int32) gpsBuffer[19] << 24) | ((int32) gpsBuffer[20] << 16) | ((int32) gpsBuffer[21] << 8) | gpsBuffer[22]; + gpsPosition.altitudeFeet = gpsPosition.altitudeCM * 100l / 3048l; + gpsPosition.vSpeed = ((uint16_t) gpsBuffer[27] << 8) | gpsBuffer[28]; + gpsPosition.hSpeed = ((uint16_t) gpsBuffer[29] << 8) | gpsBuffer[30]; + gpsPosition.heading = ((uint16_t) gpsBuffer[31] << 8) | gpsBuffer[32]; + gpsPosition.dop = ((uint16_t) gpsBuffer[33] << 8) | gpsBuffer[34]; + gpsPosition.visibleSats = gpsBuffer[35]; + gpsPosition.trackedSats = gpsBuffer[36]; + gpsPosition.status = ((uint16_t) gpsBuffer[37] << 8) | gpsBuffer[38]; -/** - * Initialize the serial processor. - */ -void serialInit() -{ - serialHead = 0; - serialTail = 0; + // Update the peak altitude if we have a valid 3D fix. + if (gpsGetFixType() == GPS_3D_FIX) + if (gpsPosition.altitudeFeet > gpsPeakAltitude) + gpsPeakAltitude = gpsPosition.altitudeFeet; } /** - * Get the oldest character from the FIFO. - * - * @return oldest character; 0 if FIFO is empty + * Turn on the GPS engine power and serial interface. */ -uint8_t serialRead() +void gpsPowerOn() { - 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; + // 3.0 VDC LDO control line. +// output_high (IO_GPS_PWR); - return value; } /** - * Read and store any characters in the PIC serial port in a FIFO. + * Turn off the GPS engine power and serial interface. */ -void serialUpdate() +void gpsPowerOff() { - // 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; - } + // 3.0 VDC LDO control line. +// output_low (IO_GPS_PWR); } /** @} */ + /** * @defgroup sys System Library Functions * @@ -2035,65 +716,6 @@ uint16_t sysCRC16(uint8_t *buffer, uint8_t length, uint16_t crc) return crc ^ 0xffff; } -/** - * Initialize the system library and global resources. - */ -void sysInit() -{ - gpsPowerOff (); - output_high (IO_LED); - - output_high (IO_CS); - output_low (IO_PS1); - output_low (IO_PS0); - output_low (IO_OSK); - output_low (IO_UPDATE); - output_low (IO_PTT); - output_low (IO_GPS_TXD); - - // Configure the port direction (input/output). - set_tris_a (0xc3); - set_tris_b (0x44); - set_tris_c (0x82); - - // Display a startup message during boot. - fprintf (PC_HOST, "System booted.\n\r"); -} - -/** - * Log the current GPS position. - */ -void sysLogGPSData() -{ - // Log the data. - logType (LOG_COORD); - logUint8 (gpsPosition.hours); - logUint8 (gpsPosition.minutes); - logUint8 (gpsPosition.seconds); - logInt32 (gpsPosition.latitude); - logInt32 (gpsPosition.longitude); - logInt32 (gpsPosition.altitudeCM); - - logUint16 (gpsPosition.vSpeed); - logUint16 (gpsPosition.hSpeed); - logUint16 (gpsPosition.heading); - - logUint16 (gpsPosition.status); - - logUint8 ((uint8_t) (gpsPosition.dop & 0xff)); - logUint8 ((uint8_t) ((gpsPosition.visibleSats << 4) | gpsPosition.trackedSats)); -} - -/** - * Log the ADC values of the bus and reference voltage values. - */ -void sysLogVoltage() -{ - logType (LOG_VOLTAGE); - logUint16 (adcRawBusVolt()); - logUint16 (adcRawRefVolt()); -} - /** @} */ /** @@ -2166,11 +788,10 @@ void timeInit() { timeTicks = 0; timeInterruptCount = 0; - time100mS = 0; +// time100mS = 0; timeSeconds = 0; timeMinutes = 0; timeHours = 0; - timeDutyCycle = TIME_DUTYCYCLE_70; timeCompare = TIME_RATE; timeUpdateFlag = false; timeNCO = 0x00; @@ -2178,12 +799,6 @@ void timeInit() timeNCOFreq = 0x2000; tncDataMode = TNC_MODE_STANDBY; timeRunFlag = false; - - // Configure CCP1 to interrupt at 1mS for PSK31 or 833uS for 1200 baud APRS - CCP_1 = TIME_RATE; - set_timer1(timeCompare); - setup_ccp1( CCP_COMPARE_INT ); - setup_timer_1( T1_INTERNAL | T1_DIV_BY_4 ); } /** @@ -2202,16 +817,6 @@ bool_t timeIsUpdate() return false; } -/** - * Set the blink duty cycle of the heartbeat LED. The LED blinks at a 1Hz rate. - * - * @param dutyCycle TIME_DUTYCYCLE_xx constant - */ -void timeSetDutyCycle (uint8_t dutyCycle) -{ - timeDutyCycle = dutyCycle; -} - /** * Set a flag to indicate the flight time should run. This flag is typically set when the payload * lifts off. @@ -2221,7 +826,6 @@ void timeSetRunFlag() timeRunFlag = true; } -#INT_CCP1 /** * Timer interrupt handler called every 104uS (9600 times/second). */ @@ -2229,7 +833,7 @@ void timeUpdate() { // Setup the next interrupt for the operational mode. timeCompare += TIME_RATE; - CCP_1 = timeCompare; +// CCP_1 = timeCompare; switch (tncDataMode) { @@ -2252,46 +856,6 @@ void timeUpdate() tnc9600TimerTick(); break; } // END switch - - // Read the GPS serial port and save any incoming characters. - serialUpdate(); - - // Count the number of milliseconds required for the tenth second counter. - if (++timeInterruptCount == 960) - { - timeInterruptCount = 0; - - // This timer just ticks every 100mS and is used for general timing. - ++timeTicks; - - // Roll the counter over every second. - if (++time100mS == 10) - { - time100mS = 0; - - // We set this flag true every second. - timeUpdateFlag = true; - - // Maintain a Real Time Clock. - if (timeRunFlag) - if (++timeSeconds == 60) - { - timeSeconds = 0; - - if (++timeMinutes == 60) - { - timeMinutes = 0; - ++timeHours; - } // END if timeMinutes - } // END if timeSeconds - } // END if time100mS - - // Flash the status LED at timeDutyCycle % per second. We use the duty cycle for mode feedback. - if (time100mS >= timeDutyCycle) - output_low (IO_LED); - else - output_high (IO_LED); - } // END if } /** @} */ @@ -2311,7 +875,7 @@ void timeUpdate() #define TNC_BUFFER_SIZE 80 /// States that define the current mode of the 1200 bps (A-FSK) state machine. -enum TNC_TX_1200BPS_STATE +typedef enum { /// Stand by state ready to accept new message. TNC_TX_READY, @@ -2327,10 +891,10 @@ enum TNC_TX_1200BPS_STATE /// Transmit the end flag sequence. TNC_TX_END -}; +} TNC_TX_1200BPS_STATE; /// Enumeration of the messages we can transmit. -enum TNC_MESSAGE_TYPE +typedef enum { /// Startup message that contains software version information. TNC_BOOT_MESSAGE, @@ -2343,13 +907,13 @@ enum TNC_MESSAGE_TYPE /// Message that contains GPS NMEA-0183 $GPRMC message. TNC_RMC -}; +} TNC_MESSAGE_TYPE; /// AX.25 compliant packet header that contains destination, station call sign, and path. /// 0x76 for SSID-11, 0x78 for SSID-12 uint8_t TNC_AX25_HEADER[30] = { 'A' << 1, 'P' << 1, 'R' << 1, 'S' << 1, ' ' << 1, ' ' << 1, 0x60, \ - 'K' << 1, 'D' << 1, '7' << 1, 'L' << 1, 'M' << 1, 'O' << 1, 0x76, \ + 'K' << 1, 'D' << 1, '7' << 1, 'S' << 1, 'Q' << 1, 'G' << 1, 0x76, \ 'G' << 1, 'A' << 1, 'T' << 1, 'E' << 1, ' ' << 1, ' ' << 1, 0x60, \ 'W' << 1, 'I' << 1, 'D' << 1, 'E' << 1, '3' << 1, ' ' << 1, 0x67, \ 0x03, 0xf0 }; @@ -2436,6 +1000,8 @@ void tncSetMode(TNC_DATA_MODE dataMode) // FSK tones at 445.947 and 445.953 MHz ddsSetFSKFreq (955382980, 955453621); break; + case TNC_MODE_STANDBY: + break; } // END switch tncDataMode = dataMode; @@ -2494,11 +1060,12 @@ void tnc1200TimerTick() case TNC_TX_SYNC: // The variable tncShift contains the lastest data byte. // NRZI enocde the data stream. - if ((tncShift & 0x01) == 0x00) + if ((tncShift & 0x01) == 0x00) { if (tncTxBit == 0) tncTxBit = 1; else tncTxBit = 0; + } // When the flag is done, determine if we need to send more or data. if (++tncBitCount == 8) @@ -2534,11 +1101,12 @@ void tnc1200TimerTick() // The variable tncShift contains the lastest data byte. // NRZI enocde the data stream. - if ((tncShift & 0x01) == 0x00) + if ((tncShift & 0x01) == 0x00) { if (tncTxBit == 0) tncTxBit = 1; else tncTxBit = 0; + } // Save the data stream so we can determine if bit stuffing is // required on the next bit time. @@ -2578,11 +1146,12 @@ void tnc1200TimerTick() // The variable tncShift contains the lastest data byte. // NRZI enocde the data stream. - if ((tncShift & 0x01) == 0x00) + if ((tncShift & 0x01) == 0x00) { if (tncTxBit == 0) tncTxBit = 1; else tncTxBit = 0; + } // Save the data stream so we can determine if bit stuffing is // required on the next bit time. @@ -2610,11 +1179,12 @@ void tnc1200TimerTick() case TNC_TX_END: // The variable tncShift contains the lastest data byte. // NRZI enocde the data stream. - if ((tncShift & 0x01) == 0x00) + if ((tncShift & 0x01) == 0x00) { if (tncTxBit == 0) tncTxBit = 1; else tncTxBit = 0; + } // If all the bits were shifted, get the next one. if (++tncBitCount == 8) @@ -2631,8 +1201,8 @@ void tnc1200TimerTick() tncDataMode = TNC_MODE_STANDBY; // Key off the DDS. - output_low (IO_OSK); - output_low (IO_PTT); +// output_low (IO_OSK); +// output_low (IO_PTT); ddsSetMode (DDS_MODE_POWERDOWN); return; @@ -2665,6 +1235,23 @@ void tncTxByte (uint8_t character) ++tncLength; } +static void +tncPrintf(char *fmt, ...) +{ + va_list ap; + int c; + + va_start(ap, fmt); + c = vsprintf((char *) tncBufferPnt, fmt, ap); + if (*fmt == '\015') + fprintf (stderr, "\n"); + else + vfprintf(stderr, fmt, ap); + va_end(ap); + tncBufferPnt += c; + tncLength += c; +} + /** * Generate the GPS NMEA standard UTC time stamp. Data is written through the tncTxByte * callback function. @@ -2672,7 +1259,7 @@ void tncTxByte (uint8_t character) void tncNMEATime() { // UTC of position fix. - printf (tncTxByte, "%02d%02d%02d,", gpsPosition.hours, gpsPosition.minutes, gpsPosition.seconds); + tncPrintf ("%02d%02d%02d,", gpsPosition.hours, gpsPosition.minutes, gpsPosition.seconds); } /** @@ -2697,7 +1284,7 @@ void tncNMEAFix() } coordMin = (coord % 3600000) / 6; - printf (tncTxByte, "%02ld%02ld.%04ld,%c,", (uint32_t) (coord / 3600000), (uint32_t) (coordMin / 10000), (uint32_t) (coordMin % 10000), dirChar); + tncPrintf ("%02ld%02ld.%04ld,%c,", (uint32_t) (coord / 3600000), (uint32_t) (coordMin / 10000), (uint32_t) (coordMin % 10000), dirChar); // Longitude value. @@ -2711,8 +1298,8 @@ void tncNMEAFix() } coordMin = (coord % 3600000) / 6; - printf (tncTxByte, "%03ld%02ld.%04ld,%c,", (uint32_t) (coord / 3600000), (uint32_t) (coordMin / 10000), (uint32_t) (coordMin % 10000), dirChar); - + tncPrintf ("%03ld%02ld.%04ld,%c,", (uint32_t) (coord / 3600000), (uint32_t) (coordMin / 10000), (uint32_t) (coordMin % 10000), dirChar); + } /** @@ -2722,7 +1309,7 @@ void tncNMEAFix() void tncGPGGAPacket() { // Generate the GPGGA message. - printf (tncTxByte, "$GPGGA,"); + tncPrintf ("$GPGGA,"); // Standard NMEA time. tncNMEATime(); @@ -2732,21 +1319,21 @@ void tncGPGGAPacket() // GPS status where 0: not available, 1: available if (gpsGetFixType() != GPS_NO_FIX) - printf (tncTxByte, "1,"); + tncPrintf ("1,"); else - printf (tncTxByte, "0,"); + tncPrintf ("0,"); // Number of visible birds. - printf (tncTxByte, "%02d,", gpsPosition.trackedSats); + tncPrintf ("%02d,", gpsPosition.trackedSats); // DOP - printf (tncTxByte, "%ld.%01ld,", gpsPosition.dop / 10, gpsPosition.dop % 10); + tncPrintf ("%ld.%01ld,", gpsPosition.dop / 10, gpsPosition.dop % 10); // Altitude in meters. - printf (tncTxByte, "%ld.%02ld,M,,M,,", (int32_t) (gpsPosition.altitudeCM / 100l), (int32_t) (gpsPosition.altitudeCM % 100)); + tncPrintf ("%ld.%02ld,M,,M,,", (int32_t) (gpsPosition.altitudeCM / 100l), (int32_t) (gpsPosition.altitudeCM % 100)); // Checksum, we add 1 to skip over the $ character. - printf (tncTxByte, "*%02X", gpsNMEAChecksum(tncBuffer + 1, tncLength - 1)); + tncPrintf ("*%02X", gpsNMEAChecksum(tncBuffer + 1, tncLength - 1)); } /** @@ -2758,83 +1345,135 @@ void tncGPRMCPacket() uint32_t temp; // Generate the GPRMC message. - printf (tncTxByte, "$GPRMC,"); + tncPrintf ("$GPRMC,"); // Standard NMEA time. tncNMEATime(); // GPS status. if (gpsGetFixType() != GPS_NO_FIX) - printf (tncTxByte, "A,"); + tncPrintf ("A,"); else - printf (tncTxByte, "V,"); + tncPrintf ("V,"); // Standard NMEA-0183 latitude/longitude. tncNMEAFix(); // Speed knots and heading. temp = (int32_t) gpsPosition.hSpeed * 75000 / 385826; - printf (tncTxByte, "%ld.%ld,%ld.%ld,", (int16_t) (temp / 10), (int16_t) (temp % 10), gpsPosition.heading / 10, gpsPosition.heading % 10); + tncPrintf ("%ld.%ld,%ld.%ld,", (int16_t) (temp / 10), (int16_t) (temp % 10), gpsPosition.heading / 10, gpsPosition.heading % 10); // Date - printf (tncTxByte, "%02d%02d%02ld,,", gpsPosition.day, gpsPosition.month, gpsPosition.year % 100); + tncPrintf ("%02d%02d%02ld,,", gpsPosition.day, gpsPosition.month, gpsPosition.year % 100); // Checksum, skip over the $ character. - printf (tncTxByte, "*%02X", gpsNMEAChecksum(tncBuffer + 1, tncLength - 1)); + tncPrintf ("*%02X", gpsNMEAChecksum(tncBuffer + 1, tncLength - 1)); +} + +/** + * Generate the plain text position packet. Data is written through the tncTxByte + * callback function + */ +void tncPositionPacket(void) +{ + int32_t latitude = 45.4694766 * 10000000; + int32_t longitude = -122.7376250 * 10000000; + uint32_t altitude = 10000; + uint16_t lat_deg; + uint16_t lon_deg; + uint16_t lat_min; + uint16_t lat_frac; + uint16_t lon_min; + uint16_t lon_frac; + + char lat_sign = 'N', lon_sign = 'E'; + +// tncPrintf (">ANSR "); + if (latitude < 0) { + lat_sign = 'S'; + latitude = -latitude; + } + + if (longitude < 0) { + lon_sign = 'W'; + longitude = -longitude; + } + + lat_deg = latitude / 10000000; + latitude -= lat_deg * 10000000; + latitude *= 60; + lat_min = latitude / 10000000; + latitude -= lat_min * 10000000; + lat_frac = (latitude + 50000) / 100000; + + lon_deg = longitude / 10000000; + longitude -= lon_deg * 10000000; + longitude *= 60; + lon_min = longitude / 10000000; + longitude -= lon_min * 10000000; + lon_frac = (longitude + 50000) / 100000; + + tncPrintf ("=%02u%02u.%02u%c\\%03u%02u.%02u%cO", + lat_deg, lat_min, lat_frac, lat_sign, + lon_deg, lon_min, lon_frac, lon_sign); + + tncPrintf (" /A=%06u", altitude * 100 / 3048); } + + /** * Generate the plain text status packet. Data is written through the tncTxByte * callback function. */ void tncStatusPacket(int16_t temperature) { - uint16_t voltage; +// uint16_t voltage; // Plain text telemetry. - printf (tncTxByte, ">ANSR "); + tncPrintf (">ANSR "); // Display the flight time. - printf (tncTxByte, "%02U:%02U:%02U ", timeHours, timeMinutes, timeSeconds); + tncPrintf ("%02u:%02u:%02u ", timeHours, timeMinutes, timeSeconds); // Altitude in feet. - printf (tncTxByte, "%ld' ", gpsPosition.altitudeFeet); + tncPrintf ("%ld' ", gpsPosition.altitudeFeet); // Peak altitude in feet. - printf (tncTxByte, "%ld'pk ", gpsGetPeakAltitude()); + tncPrintf ("%ld'pk ", gpsGetPeakAltitude()); // GPS hdop or pdop - printf (tncTxByte, "%lu.%lu", gpsPosition.dop / 10, gpsPosition.dop % 10); + tncPrintf ("%lu.%lu", gpsPosition.dop / 10, gpsPosition.dop % 10); // The text 'pdop' for a 3D fix, 'hdop' for a 2D fix, and 'dop' for no fix. switch (gpsGetFixType()) { case GPS_NO_FIX: - printf (tncTxByte, "dop "); + tncPrintf ("dop "); break; case GPS_2D_FIX: - printf (tncTxByte, "hdop "); + tncPrintf ("hdop "); break; case GPS_3D_FIX: - printf (tncTxByte, "pdop "); + tncPrintf ("pdop "); break; } // END switch // Number of satellites in the solution. - printf (tncTxByte, "%utrk ", gpsPosition.trackedSats); + tncPrintf ("%utrk ", gpsPosition.trackedSats); // Display main bus voltage. - voltage = adcGetMainBusVolt(); - printf (tncTxByte, "%lu.%02luvdc ", voltage / 100, voltage % 100); +// voltage = adcGetMainBusVolt(); +// tncPrintf ("%lu.%02luvdc ", voltage / 100, voltage % 100); // Display internal temperature. - printf (tncTxByte, "%ld.%01ldF ", temperature / 10, abs(temperature % 10)); +// tncPrintf ("%ld.%01ldF ", temperature / 10, abs(temperature % 10)); // Print web address link. - printf (tncTxByte, "www.kd7lmo.net"); + tncPrintf ("www.altusmetrum.org"); } /** @@ -2845,23 +1484,13 @@ void tncStatusPacket(int16_t temperature) */ void tncTxPacket(TNC_DATA_MODE dataMode) { - int16_t temperature; + int16_t temperature = 20; uint16_t crc; // Only transmit if there is not another message in progress. if (tncMode != TNC_TX_READY) return; - // Log the battery and reference voltage before we start the RF chain. - sysLogVoltage(); - - // We need to read the temperature sensor before we setup the DDS since they share a common clock pin. - temperature = lm92GetTemp(); - - // Log the system temperature every time we transmit a packet. - logType (LOG_TEMPERATURE); - logInt16 (temperature); - // Configure the DDS for the desired operational. tncSetMode (dataMode); @@ -2875,7 +1504,7 @@ void tncTxPacket(TNC_DATA_MODE dataMode) switch (tncPacketType) { case TNC_BOOT_MESSAGE: - printf (tncTxByte, ">ANSR Pico Beacon - V3.05"); + tncPrintf (">MegaMetrum v1.0 Beacon"); // Select the next packet we will generate. tncPacketType = TNC_STATUS; @@ -2889,7 +1518,8 @@ void tncTxPacket(TNC_DATA_MODE dataMode) break; case TNC_GGA: - tncGPGGAPacket(); + tncPositionPacket(); +// tncGPGGAPacket(); // Select the next packet we will generate. tncPacketType = TNC_RMC; @@ -2904,7 +1534,7 @@ void tncTxPacket(TNC_DATA_MODE dataMode) } // Add the end of message character. - printf (tncTxByte, "\015"); + tncPrintf ("\015"); // Calculate the CRC for the header and message. crc = sysCRC16(TNC_AX25_HEADER, sizeof(TNC_AX25_HEADER), 0xffff); @@ -2925,178 +1555,18 @@ void tncTxPacket(TNC_DATA_MODE dataMode) tncMode = TNC_TX_SYNC; // Turn on the PA chain. - output_high (IO_PTT); +// output_high (IO_PTT); // Wait for the PA chain to power up. - delay_ms (10); +// delay_ms (10); // Key the DDS. - output_high (IO_OSK); +// output_high (IO_OSK); // Log the battery and reference voltage just after we key the transmitter. - sysLogVoltage(); +// sysLogVoltage(); + while (tncMode != TNC_TX_READY) + timeUpdate(); } /** @} */ - -uint32_t counter; - -uint8_t bitIndex; -uint8_t streamIndex; -uint8_t value; - -uint8_t bitStream[] = { 0x10, 0x20, 0x30 }; - -void init() -{ - counter = 0; - bitIndex = 0; - streamIndex = 0; - value = bitStream[0]; -} - -void test() -{ - counter += 0x10622d; - - CCP_1 = (uint16_t) ((counter >> 16) & 0xffff); - - if ((value & 0x80) == 0x80) - setup_ccp1 (CCP_COMPARE_SET_ON_MATCH); - else - setup_ccp1 (CCP_COMPARE_CLR_ON_MATCH); - - if (++bitIndex == 8) - { - bitIndex = 0; - - if (++streamIndex == sizeof(bitStream)) - { - streamIndex = 0; - } - - value = bitStream[streamIndex]; - } else - value = value << 1; -} - -// This is where we go after reset. -void main() -{ - uint8_t i, utcSeconds, lockLostCounter; - -test(); - - // Configure the basic systems. - sysInit(); - - // Wait for the power converter chains to stabilize. - delay_ms (100); - - // Setup the subsystems. - adcInit(); - flashInit(); - gpsInit(); - logInit(); - timeInit(); - serialInit(); - tncInit(); - - // Program the DDS. - ddsInit(); - - // Turn off the LED after everything is configured. - output_low (IO_LED); - - // Check for the diagnostics plug, otherwise we'll continue to boot. - diagPort(); - - // Setup our interrupts. - enable_interrupts(GLOBAL); - enable_interrupts(INT_CCP1); - - // Turn on the GPS engine. - gpsPowerOn(); - - // Allow the GPS engine to boot. - delay_ms (250); - - // Initialize the GPS engine. - while (!gpsSetup()); - - // Charge the ADC filters. - for (i = 0; i < 32; ++i) - adcUpdate(); - - // Log startup event. - logType (LOG_BOOTED); - logUint8 (gpsPosition.month); - logUint8 (gpsPosition.day); - logUint8 (gpsPosition.year & 0xff); - - logUint8 (gpsPosition.hours); - logUint8 (gpsPosition.minutes); - logUint8 (gpsPosition.seconds); - - // Transmit software version packet on start up. - tncTxPacket(TNC_MODE_1200_AFSK); - - // Counters to send packets if the GPS time stamp is not available. - lockLostCounter = 5; - utcSeconds = 55; - - // This is the main loop that process GPS data and waits for the once per second timer tick. - for (;;) - { - // Read the GPS engine serial port FIFO and process the GPS data. - gpsUpdate(); - - if (gpsIsReady()) - { - // Start the flight timer when we get a valid 3D fix. - if (gpsGetFixType() == GPS_3D_FIX) - timeSetRunFlag(); - - // Generate our packets based on the GPS time. - if (tncIsTimeSlot(gpsPosition.seconds)) - tncTxPacket(TNC_MODE_1200_AFSK); - - // Sync the internal clock to GPS UTC time. - utcSeconds = gpsPosition.seconds; - - // This counter is reset every time we receive the GPS message. - lockLostCounter = 0; - - // Log the data to flash. - sysLogGPSData(); - } // END if gpsIsReady - - // Processing that occurs once a second. - if (timeIsUpdate()) - { - // We maintain the UTC time in seconds if we shut off the GPS engine or it fails. - if (++utcSeconds == 60) - utcSeconds = 0; - - // If we loose information for more than 5 seconds, - // we will determine when to send a packet based on internal time. - if (lockLostCounter == 5) - { - if (tncIsTimeSlot(utcSeconds)) - tncTxPacket(TNC_MODE_1200_AFSK); - } else - ++lockLostCounter; - - // Update the ADC filters. - adcUpdate(); - - if (timeHours == 5 && timeMinutes == 0 && timeSeconds == 0) - gpsPowerOff(); - - } // END if timeIsUpdate - - } // END for -} - - -