psk31beacon.c

Go to the documentation of this file.
00001 
00080 // Hardware specific configuration.
00081 #include <18f252.h>
00082 #device ADC=10
00083 
00084 // NOTE: Even though we are using an external clock, we set the HS oscillator mode to
00085 //       make the PIC 18F252 work with our external clock which is a clipped 1V P-P sine wave.
00086 #fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
00087 
00088 // C runtime library definitions.
00089 #include <stdlib.h>
00090 #include <string.h>
00091 
00092 // TCXO frequency
00093 #use delay(clock=19200000)
00094 
00095 // Engineering and data extracation port.
00096 #use rs232(baud=57600, xmit=PIN_B7, rcv=PIN_B6, stream=PC_HOST)
00097 
00098 // GPS engine
00099 #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
00100 
00101 #use fast_io(A)
00102 #use fast_io(B)
00103 #use fast_io(C)
00104 
00105 // We define types that are used for all variables.  These are declared
00106 // because each processor has a different sizes for int and long.
00107 // The PIC compiler defines int8_t, int16_t, and int32_t.
00108 
00110 typedef boolean bool_t;
00111 
00113 typedef signed int8 int8_t;
00114 
00116 typedef unsigned int8 uint8_t;
00117 
00119 typedef signed int16 int16_t;
00120 
00122 typedef unsigned int16 uint16_t;
00123 
00125 typedef signed int32 int32_t;
00126 
00128 typedef unsigned int32 uint32_t;
00129 
00130 // Function and structure prototypes.  These are declared at the start of
00131 // the file much like a C++ header file.
00132 
00133 // Map I/O names to the hardware pins.
00134 
00136 #define IO_FLASH_CS PIN_A0
00137 
00138 #define IO_CUT_DOWN PIN_A1
00139 
00140 #define IO_BALLAST_PUMP PIN_A2
00141 
00142 #define IO_PS0 PIN_A3
00143 #define IO_UPDATE PIN_A5
00144 
00145 #define IO_CS PIN_B0
00146 #define IO_PA PIN_B2
00147 #define IO_GPS_PWR PIN_B3
00148 #define IO_LED PIN_B4
00149 
00150 #define IO_PS1 PIN_C0
00151 #define IO_OSK PIN_C2
00152 
00153 // Serial port enable RCSTA
00154 #bit SPEN = 0xfab.7
00155 
00156 bool_t cutDownIsActivate();
00157 
00159 typedef enum 
00160 {
00162     DDS_MODE_POWERDOWN,
00163 
00165     DDS_MODE_APRS,
00166 
00168     DDS_MODE_PSK31,
00169 
00171     DDS_MODE_HF_APRS
00172 } DDS_MODE;
00173 
00174 void ddsInit();
00175 void ddsPhase (bool_t phase);
00176 void ddsSetOutputScale (uint16_t scale);
00177 void ddsSetAmplitude (uint8_t amplitude);
00178 inline void ddsPTT (bool_t state);
00179 void ddsSetFreq (uint32_t freq);
00180 void ddsSetFTW (uint32_t ftw);
00181 void ddsSetMode (DDS_MODE mode);
00182 
00183 void flashErase();
00184 uint8_t flashGetByte ();
00185 uint8_t flashReadElectronicSignature();
00186 void flashReadBlock(uint32_t address, uint8_t *block, uint16_t length);
00187 void flashSendByte(uint8_t value);
00188 void flashSendAddress(uint32_t address);
00189 void flashWriteBlock(uint32_t address, uint8_t *block, uint8_t length);
00190 uint8_t flashReadES();
00191 
00193 typedef enum  
00194 {
00196     GPS_NO_FIX,
00197 
00199     GPS_2D_FIX,
00200 
00202     GPS_3D_FIX
00203 } GPS_FIX_TYPE;
00204 
00206 typedef struct 
00207 {
00209     bool_t updateFlag;
00210 
00212     uint8_t month;
00213 
00215     uint8_t day;
00216 
00218     uint8_t hours;
00219 
00221     uint8_t minutes;
00222 
00224     uint8_t seconds;
00225 
00227     uint16_t year;
00228 
00230     int32_t latitude;
00231 
00233     int32_t longitude;
00234 
00236     int32_t altitudeCM;
00237 
00239     int32_t altitudeFeet;
00240 
00242     uint16_t vSpeed;
00243 
00245     uint16_t hSpeed;
00246 
00248     uint16_t heading;
00249 
00251     uint16_t dop;
00252 
00254     uint16_t status;
00255 
00257     uint8_t trackedSats;
00258 
00260     uint8_t visibleSats;
00261 } GPSPOSITION_STRUCT;
00262 
00264 GPSPOSITION_STRUCT gpsPosition;
00265 
00266 void gpsInit();
00267 bool_t gpsIsReady();
00268 GPS_FIX_TYPE gpsGetFixType();
00269 int32_t gpsGetPeakAltitude();
00270 void gpsPowerOn();
00271 void gpsPowerOff();
00272 bool_t gpsSetup();
00273 void gpsUpdate();
00274 
00275 int16_t lm92GetTemp();
00276 
00278 typedef enum  
00279 {
00281     LOG_BOOTED = 0xb4,
00282 
00284     LOG_COORD = 0xa5,
00285 
00287     LOG_TEMPERATURE_1 = 0x96,
00288 
00290     LOG_VOLTAGE = 0x87,
00291 
00293     LOG_TEMPERATURE_2 = 0x78,
00294 
00296     LOG_PUMP = 0x69
00297 } LOG_TYPE;
00298 
00299 void logInit();
00300 uint32_t logGetAddress();
00301 void logSetDisableFlag (bool_t disableFlag);
00302 void logType (LOG_TYPE type);
00303 void logUint8 (uint8_t value);
00304 void logInt16 (int16_t value);
00305 void logInt32 (int32_t value);
00306 
00307 bool_t psk31CreateDataPacket();
00308 void psk31Init();
00309 void psk31TimeUpdate();
00310 void psk31TxPacket(uint8_t minutes);
00311 void psk31TxByte (uint8_t value);
00312 void psk31TxNull ();
00313 void psk31TxString (char *string, uint8_t length);
00314 
00315 bool_t serialHasData();
00316 void serialInit();
00317 uint8_t serialRead();
00318 void serialUpdate();
00319 
00320 uint16_t sysCRC16(uint8_t *buffer, uint8_t length, uint16_t crc);
00321 inline void sysPAOutput (bool_t state);
00322 
00323 // Constants for time duty cycle in method timeSetDutyCycle
00324 #define TIME_DUTYCYCLE_0 0
00325 #define TIME_DUTYCYCLE_20 2
00326 #define TIME_DUTYCYCLE_70 7
00327 
00328 // Constants for the time base mode in method timeSetMode
00329 typedef enum 
00330 {
00331     TIME_MODE_APRS,
00332     TIME_MODE_PSK31,
00333     TIME_MODE_HF_APRS
00334 } TIME_MODE;
00335 
00336 uint8_t timeGetTicks();
00337 void timeInit();
00338 uint8_t timeGetHours();
00339 uint8_t timeGetMinutes();
00340 void timeSetDutyCycle (uint8_t dutyCycle);
00341 void timeSetMode (TIME_MODE mode);
00342 void timeUpdate();
00343 
00344 // Modes for the packet state machine.
00345 typedef enum 
00346 {
00347     TNC_BOOT_MESSAGE,
00348     TNC_STATUS,
00349     TNC_GGA,
00350     TNC_RMC
00351 } TNC_PACKET_TYPE;
00352 
00353 void tncInit();
00354 bool_t tncIsFree();
00355 void tncTimeUpdate();
00356 void tncTxByte (uint8_t value);
00357 void tncTxPacket(TNC_PACKET_TYPE tncPacketType);
00358 
00367 
00368 #define BALLAST_3D_FIX_COUNT 10
00369 
00371 #define BALLAST_HOLD_ALTITUDE 30500l
00372 
00374 enum BALLAST_MODE
00375 {
00377     WAIT_ACTIVATION,
00378 
00380     CONTROL_ALTITUDE,
00381 
00383     PUMP_RUN,
00384 
00386     PUMP_RUN_DELAY
00387 };
00388 
00390 uint16_t ballastPumpCount;
00391 
00393 uint8_t ballast3DFixCount;
00394 
00396 uint8_t ballastTimeCount;
00397 
00399 BALLAST_MODE ballastMode;
00400 
00402 bool_t ballastState;
00403 
00409 uint16_t ballastGetPumpCount()
00410 {
00411     return ballastPumpCount;
00412 }
00413 
00417 void ballastInit()
00418 {
00419     ballastPumpCount = 0;
00420     ballastTimeCount = 0;
00421     ballast3DFixCount = 0;
00422     ballastState = true;
00423     ballastMode = WAIT_ACTIVATION;
00424 }
00425 
00431 void ballastSetState (bool_t state)
00432 {
00433     ballastState = state;
00434 }
00435 
00441 void ballastLogEvent (bool_t state)
00442 {
00443     logType (LOG_PUMP);
00444     logUint8 ((state ? 0x01 : 0x00));
00445     logUint8 (gpsPosition.hours);
00446     logUint8 (gpsPosition.minutes);
00447     logUint8 (gpsPosition.seconds);
00448     logInt32 (gpsPosition.altitudeCM);
00449 }
00450 
00455 void ballastCheck()
00456 {
00457     if (!ballastState)
00458     {
00459         ballast3DFixCount = 0;
00460         return;
00461     } // END if
00462 
00463     if (gpsGetFixType() == GPS_3D_FIX)
00464     {
00465         if (ballast3DFixCount < BALLAST_3D_FIX_COUNT)
00466             ++ballast3DFixCount;
00467     } else
00468         ballast3DFixCount = 0;
00469 
00470     // State machine that controls the ballast pump operation.
00471     switch (ballastMode)
00472     {
00473         case WAIT_ACTIVATION:
00474             if (ballast3DFixCount == BALLAST_3D_FIX_COUNT)
00475                 if (gpsPosition.altitudeFeet > BALLAST_HOLD_ALTITUDE)
00476                 {
00477                     ++ballastPumpCount;
00478                     ballastMode = CONTROL_ALTITUDE;
00479                 } // END if
00480 
00481             // If we aren't at altitude after 90 minutes, enable the ballast pump.
00482             if (timeGetHours() == 1 && timeGetMinutes() == 30)
00483             {
00484                 ++ballastPumpCount;
00485                 ballastMode = CONTROL_ALTITUDE;
00486             }
00487 
00488             break;
00489 
00490         case CONTROL_ALTITUDE:
00491             if (ballast3DFixCount == BALLAST_3D_FIX_COUNT)
00492                 if (gpsPosition.altitudeFeet < BALLAST_HOLD_ALTITUDE)
00493                 {
00494                     output_high (IO_BALLAST_PUMP);
00495                     
00496                     ballastLogEvent (true);
00497 
00498                     ballastTimeCount = 0;
00499 
00500                     ballastMode = PUMP_RUN;
00501                 } // END if
00502             break;
00503 
00504         case PUMP_RUN:
00505             if (++ballastTimeCount == 5)
00506             {
00507                 output_low (IO_BALLAST_PUMP);
00508 
00509                 ballastLogEvent (false);
00510 
00511                 ++ballastPumpCount;
00512 
00513                 ballastTimeCount = 0;
00514                 ballastMode = PUMP_RUN_DELAY;
00515             } // END if
00516 
00517             break;
00518 
00519         case PUMP_RUN_DELAY:
00520             if (++ballastTimeCount == 60)
00521                 ballastMode = CONTROL_ALTITUDE;
00522             break;
00523     } // END switch
00524 }
00525 
00536 
00537 #define CUTDOWN_3D_FIX_COUNT 10
00538 
00540 uint8_t cutDownTimer;
00541 
00543 uint8_t cutDown3DFixCount;
00544 
00546 bool_t cutDownFlag;
00547 
00553 bool_t cutDownIsActivate()
00554 {
00555     return cutDownFlag;
00556 }
00557 
00561 void cutDownInit()
00562 {
00563     cutDownFlag = false;
00564     cutDownTimer = 0;   
00565     cutDown3DFixCount = 0;
00566 }
00567 
00571 void cutDownActivate()
00572 {
00573     output_high (IO_CUT_DOWN);
00574     cutDownTimer = 7;
00575     cutDownFlag = true;
00576 }
00577 
00581 void cutDownCheck()
00582 {
00583     // Turn off the timer after a period of time.
00584     if (cutDownTimer != 0)
00585         if (--cutDownTimer == 0)
00586             output_low (IO_CUT_DOWN);
00587 
00588     // Once the cut down has fired, we are done with it.
00589     if (cutDownFlag)
00590         return;
00591 
00592     // Terminate the flight after 49 hours.  (One hour on the ground, 48 in flight).
00593     if (timeGetHours() == 49)
00594         cutDownActivate();
00595 
00596     // We need to see a number of consecutive 3D GPS fixes to use the altitude.
00597     if (gpsGetFixType() == GPS_3D_FIX)
00598     {
00599         if (cutDown3DFixCount < CUTDOWN_3D_FIX_COUNT)
00600             ++cutDown3DFixCount;
00601     } else
00602         cutDown3DFixCount = 0;
00603 
00604     // If we are EAST of 83 degrees WEST latitude, terminate the flight.
00605     if (cutDown3DFixCount == CUTDOWN_3D_FIX_COUNT)
00606         if (gpsPosition.longitude > -298800000)
00607             cutDownActivate();
00608 }
00609 
00620 
00621 #define DDS_AD9954_CFR1 0x00
00622 
00624 #define DDS_AD9954_CFR2 0x01
00625 
00627 #define DDS_AD9954_ASF 0x02
00628 
00630 #define DDS_AD9954_ARR 0x03
00631 
00633 #define DDS_AD9954_FTW0 0x04
00634 
00636 #define DDS_AD9954_FTW1 0x06
00637 
00639 #define DDS_AD9954_NLSCW 0x07
00640 
00642 #define DDS_AD9954_PLSCW 0x08
00643 
00645 #define DDS_AD9954_RWCW0 0x07
00646 
00648 #define DDS_AD9954_RWCW1 0x08
00649 
00651 #define DDS_RAM 0x0b
00652 
00654 #define DDS_FREQ_TO_FTW_DIGITS 9
00655 
00657 const uint32_t DDS_MULT[DDS_FREQ_TO_FTW_DIGITS] = { 11, 1, 8, 4, 8, 1, 0, 6, 6 };
00658 
00660 const uint32_t DDS_DIVISOR[DDS_FREQ_TO_FTW_DIGITS - 1] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
00661 
00663 const uint16_t DDS_AMP_TO_SCALE[] = { 16383, 15467, 14601, 13785,  13013, 12286, 11598, 10949,  10337, 9759, 9213, 8697, 
00664 8211, 7752, 7318, 6909,  6522, 6157, 5813, 5488,  5181, 4891, 4617, 4359,  4115, 3885, 3668, 3463, 
00665 3269, 3086, 2913, 2750,  2597, 2451, 2314, 2185,  2062, 1947, 1838, 1735,  1638 };
00666 
00667 // Frequency Word List - 5.0KHz FM frequency deviation at 50.62Mhz
00668 const uint32_t freqTable[256] = 
00669 {
00670 566175115
00671 ,566176488
00672 ,566177860
00673 ,566179229
00674 ,566180597
00675 ,566181961
00676 ,566183321
00677 ,566184676
00678 ,566186026
00679 ,566187368
00680 ,566188704
00681 ,566190031
00682 ,566191349
00683 ,566192658
00684 ,566193956
00685 ,566195242
00686 ,566196517
00687 ,566197778
00688 ,566199026
00689 ,566200260
00690 ,566201478
00691 ,566202680
00692 ,566203866
00693 ,566205035
00694 ,566206185
00695 ,566207317
00696 ,566208429
00697 ,566209522
00698 ,566210593
00699 ,566211644
00700 ,566212672
00701 ,566213677
00702 ,566214660
00703 ,566215618
00704 ,566216552
00705 ,566217462
00706 ,566218345
00707 ,566219203
00708 ,566220034
00709 ,566220838
00710 ,566221615
00711 ,566222363
00712 ,566223083
00713 ,566223774
00714 ,566224436
00715 ,566225068
00716 ,566225670
00717 ,566226242
00718 ,566226783
00719 ,566227292
00720 ,566227770
00721 ,566228217
00722 ,566228631
00723 ,566229014
00724 ,566229364
00725 ,566229681
00726 ,566229965
00727 ,566230216
00728 ,566230434
00729 ,566230619
00730 ,566230770
00731 ,566230888
00732 ,566230972
00733 ,566231023
00734 ,566231040
00735 ,566231023
00736 ,566230972
00737 ,566230888
00738 ,566230770
00739 ,566230619
00740 ,566230434
00741 ,566230216
00742 ,566229965
00743 ,566229681
00744 ,566229364
00745 ,566229014
00746 ,566228631
00747 ,566228217
00748 ,566227770
00749 ,566227292
00750 ,566226783
00751 ,566226242
00752 ,566225670
00753 ,566225068
00754 ,566224436
00755 ,566223774
00756 ,566223083
00757 ,566222363
00758 ,566221615
00759 ,566220838
00760 ,566220034
00761 ,566219203
00762 ,566218345
00763 ,566217462
00764 ,566216552
00765 ,566215618
00766 ,566214660
00767 ,566213677
00768 ,566212672
00769 ,566211644
00770 ,566210593
00771 ,566209522
00772 ,566208429
00773 ,566207317
00774 ,566206185
00775 ,566205035
00776 ,566203866
00777 ,566202680
00778 ,566201478
00779 ,566200260
00780 ,566199026
00781 ,566197778
00782 ,566196517
00783 ,566195242
00784 ,566193956
00785 ,566192658
00786 ,566191349
00787 ,566190031
00788 ,566188704
00789 ,566187368
00790 ,566186026
00791 ,566184676
00792 ,566183321
00793 ,566181961
00794 ,566180597
00795 ,566179229
00796 ,566177860
00797 ,566176488
00798 ,566175115
00799 ,566173743
00800 ,566172371
00801 ,566171001
00802 ,566169634
00803 ,566168270
00804 ,566166910
00805 ,566165555
00806 ,566164205
00807 ,566162862
00808 ,566161527
00809 ,566160200
00810 ,566158882
00811 ,566157573
00812 ,566156275
00813 ,566154989
00814 ,566153714
00815 ,566152453
00816 ,566151205
00817 ,566149971
00818 ,566148753
00819 ,566147551
00820 ,566146365
00821 ,566145196
00822 ,566144046
00823 ,566142914
00824 ,566141802
00825 ,566140709
00826 ,566139638
00827 ,566138587
00828 ,566137559
00829 ,566136554
00830 ,566135571
00831 ,566134613
00832 ,566133678
00833 ,566132769
00834 ,566131886
00835 ,566131028
00836 ,566130197
00837 ,566129393
00838 ,566128616
00839 ,566127868
00840 ,566127148
00841 ,566126457
00842 ,566125795
00843 ,566125163
00844 ,566124561
00845 ,566123989
00846 ,566123448
00847 ,566122939
00848 ,566122460
00849 ,566122014
00850 ,566121599
00851 ,566121217
00852 ,566120867
00853 ,566120550
00854 ,566120266
00855 ,566120015
00856 ,566119797
00857 ,566119612
00858 ,566119461
00859 ,566119343
00860 ,566119259
00861 ,566119208
00862 ,566119191
00863 ,566119208
00864 ,566119259
00865 ,566119343
00866 ,566119461
00867 ,566119612
00868 ,566119797
00869 ,566120015
00870 ,566120266
00871 ,566120550
00872 ,566120867
00873 ,566121217
00874 ,566121599
00875 ,566122014
00876 ,566122460
00877 ,566122939
00878 ,566123448
00879 ,566123989
00880 ,566124561
00881 ,566125163
00882 ,566125795
00883 ,566126457
00884 ,566127148
00885 ,566127868
00886 ,566128616
00887 ,566129393
00888 ,566130197
00889 ,566131028
00890 ,566131886
00891 ,566132769
00892 ,566133678
00893 ,566134613
00894 ,566135571
00895 ,566136554
00896 ,566137559
00897 ,566138587
00898 ,566139638
00899 ,566140709
00900 ,566141802
00901 ,566142914
00902 ,566144046
00903 ,566145196
00904 ,566146365
00905 ,566147551
00906 ,566148753
00907 ,566149971
00908 ,566151205
00909 ,566152453
00910 ,566153714
00911 ,566154989
00912 ,566156275
00913 ,566157573
00914 ,566158882
00915 ,566160200
00916 ,566161527
00917 ,566162862
00918 ,566164205
00919 ,566165555
00920 ,566166910
00921 ,566168270
00922 ,566169634
00923 ,566171001
00924 ,566172371
00925 ,566173743
00926 };
00927 
00928 
00932 void ddsInit()
00933 {
00934     // Set default I/O for the DDS.
00935     output_high (IO_CS);
00936     output_low (IO_PS1);
00937     output_low (IO_PS0);
00938     output_low (IO_OSK);
00939     output_low (IO_UPDATE);
00940 
00941     // Setup the SPI port for the DDS interface.    
00942     setup_spi( SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H );    
00943 
00944     // Turn off the output.
00945     output_low (IO_OSK);
00946 
00947     ddsSetMode (DDS_MODE_POWERDOWN);
00948 
00949     // ASF (Amplitude Scale Factor) to full scale (0x3fff).
00950     ddsSetOutputScale (0x3fff);
00951 
00952     // ARR (Amplitude Ramp Rate) to 15.5mS for OSK
00953     output_low (IO_CS);
00954     spi_write (DDS_AD9954_ARR);
00955 
00956     spi_write (181);
00957     output_high (IO_CS);
00958 
00959     // CFR2 (Control Function Register No. 2)
00960     output_low (IO_CS);
00961     spi_write (0x01);
00962 
00963     spi_write (0x00);     // Unused register bits
00964     spi_write (0x00);
00965     spi_write (0xa4);     // 20x reference clock multipler, high VCO range, nominal charge pump current
00966     output_high (IO_CS);
00967 
00968     // Strobe the part so we apply the updates.
00969     output_high (IO_UPDATE);
00970     output_low (IO_UPDATE);
00971 }
00972 
00979 void ddsSetOutputScale (uint16_t scale)
00980 {
00981     // Set ASF (Amplitude Scale Factor)
00982     output_low (IO_CS);
00983     spi_write (DDS_AD9954_ASF);
00984 
00985     spi_write ((scale >> 8) & 0xff);
00986     spi_write (scale & 0xff);
00987 
00988     output_high (IO_CS);
00989     
00990     // Strobe the DDS to set the amplitude.
00991     output_high (IO_UPDATE);
00992     output_low (IO_UPDATE);
00993 }
00994 
01001 void ddsSetAmplitude (uint8_t amplitude)
01002 {
01003     // Range limit based on the lookup table size.
01004     if (amplitude > 200)
01005         return;
01006 
01007     // Set the linear DDS ASF (Amplitude Scale Factor) based on the dB lookup table.
01008     ddsSetOutputScale (DDS_AMP_TO_SCALE[amplitude / 5]);
01009 
01010     // Toggle the DDS output low and then high to force it to ramp to the new output level setting.
01011     output_low (IO_OSK);
01012     delay_ms(25); 
01013 
01014     output_high (IO_OSK);
01015     delay_ms(25); 
01016 }
01017 
01024 void ddsSetFreq(uint32_t freq)
01025 {
01026     uint8_t i;
01027     uint32_t ftw;
01028     
01029     // To avoid rounding errors with floating point math, we do a long multiply on the data.
01030     ftw = freq * DDS_MULT[0];
01031     
01032     for (i = 0; i < DDS_FREQ_TO_FTW_DIGITS - 1; ++i)
01033         ftw += (freq * DDS_MULT[i+1]) / DDS_DIVISOR[i];
01034     
01035     ddsSetFTW (ftw);
01036 }
01037 
01043 void ddsPhase (bool_t phase)
01044 {
01045     // Set the POW0 (Phase Offset Word 0) to 0 or 180 degrees.
01046     output_low (IO_CS);
01047     spi_write (0x05);   
01048 
01049     if (phase) 
01050     {
01051         spi_write (0x20);
01052         spi_write (0x00);
01053     } else {
01054         spi_write (0x00);
01055         spi_write (0x00);
01056     }
01057 
01058     output_high (IO_CS);
01059 
01060     // Strobe the DDS to write the phase change.
01061     output_high (IO_UPDATE);
01062     output_low (IO_UPDATE);
01063 }
01064 
01070 inline void ddsPTT (bool_t state)
01071 {
01072     if (state)
01073         output_high (IO_OSK);
01074     else
01075         output_low (IO_OSK);
01076 }
01077 
01083 void ddsSetFTW (uint32_t ftw)
01084 {
01085     // Set FTW0 (Frequency Tuning Word 0)
01086     output_low (IO_CS);
01087     spi_write (DDS_AD9954_FTW0);
01088 
01089     spi_write ((ftw >> 24) & 0xff);
01090     spi_write ((ftw >> 16) & 0xff);
01091     spi_write ((ftw >> 8) & 0xff);
01092     spi_write (ftw & 0xff);
01093 
01094     output_high (IO_CS);
01095     
01096     // Strobe the DDS to set the frequency.
01097     output_high (IO_UPDATE);
01098     output_low (IO_UPDATE);     
01099 }
01100 
01106 void ddsSetMode (DDS_MODE mode)
01107 {
01108     switch (mode) 
01109     {
01110         case DDS_MODE_POWERDOWN:
01111             // CFR1 (Control Function Register No. 1)
01112             output_low (IO_CS);
01113             spi_write (DDS_AD9954_CFR1);
01114         
01115             spi_write (0x00);
01116             spi_write (0x00);
01117             spi_write (0x00);
01118             spi_write (0xf0);  // Power down all subsystems.
01119             output_high (IO_CS);
01120             break;
01121 
01122         case DDS_MODE_APRS:
01123             // CFR0 (Control Function Register No. 1)
01124             output_low (IO_CS);
01125             spi_write (DDS_AD9954_CFR1);
01126 
01127             spi_write (0x03);  // Clear RAM Enable, OSK Enable, Auto OSK keying
01128             spi_write (0x00);
01129             spi_write (0x02);  // SDIO input only
01130             spi_write (0x40);  // Power down comparator circuit
01131             output_high (IO_CS);
01132             break;
01133             
01134         case DDS_MODE_PSK31:
01135             // CFR0 (Control Function Register No. 1)
01136             output_low (IO_CS);
01137             spi_write (DDS_AD9954_CFR1);
01138 
01139             spi_write (0x03);  // Clear RAM Enable, OSK Enable, Auto OSK keying
01140             spi_write (0x00);
01141             spi_write (0x02);  // SDIO input only
01142             spi_write (0x40);  // Power down comparator circuit
01143             output_high (IO_CS);
01144             break;
01145 
01146         case DDS_MODE_HF_APRS:
01147             // CFR0 (Control Function Register No. 1)
01148             output_low (IO_CS);
01149             spi_write (DDS_AD9954_CFR1);
01150 
01151             spi_write (0x03);  // Clear RAM Enable, OSK Enable, Auto OSK keying
01152             spi_write (0x20);  // Enable linear sweep
01153             spi_write (0x02);  // SDIO input only
01154             spi_write (0x40);  // Power down comparator circuit
01155             output_high (IO_CS);
01156 
01157             // NOTE: The sweep rate requires 1/4 of a bit time to transition.
01158             // 200Hz delta = 2236 counts  (200Hz / 384MHz) * 2 ^ 32
01159             // SYNC_CLK = 96MHz  1/96MHz * 2236 * 36 = 838uS
01160 
01161             // NLSCW (Negative Linear Sweep Control Word)
01162             output_low (IO_CS);
01163             spi_write (DDS_AD9954_NLSCW);
01164 
01165             spi_write (36);    // Falling sweep ramp rate word
01166             spi_write (0x00);  // Delta frequency tuning word
01167             spi_write (0x00);
01168             spi_write (0x00);
01169             spi_write (0x01); 
01170             output_high (IO_CS);
01171 
01172             // PLSCW (Positive Linear Sweep Control Word)
01173             output_low (IO_CS);
01174             spi_write (DDS_AD9954_PLSCW);
01175 
01176             spi_write (36);    // Falling sweep ramp rate word
01177             spi_write (0x00);  // Delta frequency tuning word
01178             spi_write (0x00);
01179             spi_write (0x00);
01180             spi_write (0x01); 
01181             output_high (IO_CS);
01182             break;
01183             
01184     } // END switch
01185     
01186     // Strobe the DDS to change the mode.
01187     output_high (IO_UPDATE);
01188     output_low (IO_UPDATE);      
01189 }
01190 
01202 
01203 #define DIAG_BYTES_PER_LINE 32
01204 
01208 void diagEraseFlash()
01209 {
01210     // Confirm we want to erase the flash with the key sequence 'yes' <RETURN>.
01211     fprintf (PC_HOST, "Are you sure (yes)?  ");
01212 
01213     if (fgetc(PC_HOST) != 'y')
01214         return;
01215 
01216     if (fgetc(PC_HOST) != 'e')
01217         return;
01218 
01219     if (fgetc(PC_HOST) != 's')
01220         return;
01221 
01222     if (fgetc(PC_HOST) != 13)
01223         return;
01224 
01225     // User feedback and erase the part.
01226     fprintf (PC_HOST, "\n\rErasing flash...");
01227 
01228     flashErase();
01229 
01230     fprintf (PC_HOST, "done.\n\r");
01231 }
01232 
01236 void diagReadFlash()
01237 {
01238     bool_t dataFoundFlag, userStopFlag;
01239     uint8_t i, buffer[DIAG_BYTES_PER_LINE];
01240     uint32_t address;
01241 
01242     // Set the initial conditions to read the flash.
01243     address = 0x0000;
01244     userStopFlag = false;
01245 
01246     do 
01247     {
01248         // Read each block from the flash device.
01249         flashReadBlock (address, buffer, DIAG_BYTES_PER_LINE);
01250 
01251         // This flag will get set if any data byte is not equal to 0xff (erase flash state)
01252         dataFoundFlag = false;
01253 
01254         // Display the address.
01255         fprintf (PC_HOST, "%03lx ", address);
01256 
01257         // Display each byte in the line.
01258         for (i = 0; i < DIAG_BYTES_PER_LINE; ++i) 
01259         {
01260             fprintf (PC_HOST, "%02x", buffer[i]);
01261 
01262             // Set this flag if the cell is not erased.
01263             if (buffer[i] != 0xff)
01264                 dataFoundFlag = true;
01265 
01266             // Any key will abort the transfer.
01267             if (kbhit(PC_HOST))
01268                 userStopFlag = true;
01269         } // END for
01270 
01271         // <CR><LF> at the end of each line.
01272         fprintf (PC_HOST, "\n\r");
01273 
01274         // Advance to the next block of memory.
01275         address += DIAG_BYTES_PER_LINE;
01276     } while (dataFoundFlag && !userStopFlag);
01277 
01278     // Feedback to let the user know why the transfer stopped.
01279     if (userStopFlag)
01280         fprintf (PC_HOST, "User aborted download!\n\r");
01281 }
01282 
01286 void diagMenu()
01287 {
01288     // User interface.
01289     fprintf (PC_HOST, "Options: (e)rase Flash, (r)ead Flash\n\r");
01290     fprintf (PC_HOST, "         Toggle (L)ED, Toggle RF (P)A, Toggle Ban(d)\n\r");
01291     fprintf (PC_HOST, "         Toggle (n)ichrome wire, Toggle ballast p(u)mp\n\r");
01292     fprintf (PC_HOST, "         (t)emperature sensor value\n\r");
01293     fprintf (PC_HOST, "         (f)requencey down, (F)requency up - 10Hz step\n\r");
01294     fprintf (PC_HOST, "         (c)hannel down, (C)hannel up - 1KHz step\n\r");
01295     fprintf (PC_HOST, "         (a)mplitude down, (A)mplitude up - 0.5 dB steps\n\r");
01296     fprintf (PC_HOST, "         Re(b)oot processor\n\r");
01297     fprintf (PC_HOST, "         e(x)it engineering mode\n\r");
01298 }
01299 
01303 void diagPort()
01304 {
01305     bool_t diagDoneFlag, ledFlag, paFlag, showSettingsFlag, phaseFlag, cutdownFlag, pumpFlag;
01306     bool_t lowBandFlag;
01307     uint8_t command, amplitude;
01308     int16_t temperature, tcxo;
01309     uint32_t freqHz;
01310 
01311     // If the input is low, we aren't connected to the RS-232 device so continue to boot.
01312     if (!input(PIN_B6))
01313         return;
01314 
01315     fprintf (PC_HOST, "Engineering Mode\n\r");
01316     fprintf (PC_HOST, "Application Built %s %s\n\r", __DATE__, __TIME__);
01317 
01318     // Current state of the status LED.
01319     ledFlag = false;
01320     output_bit (IO_LED, ledFlag);
01321 
01322     // This flag indicates we are ready to leave the diagnostics mode.
01323     diagDoneFlag = false;
01324 
01325     // Current state of the PA.
01326     paFlag = false;
01327 
01328     cutdownFlag = false;
01329 
01330     lowBandFlag = true;
01331 
01332     pumpFlag = false;
01333 
01334     // Flag that indicate we should show the current carrier frequency.
01335     showSettingsFlag = false;
01336 
01337     // Set the initial carrier frequency and amplitude.
01338     freqHz = 14070450;
01339     amplitude = 100;
01340     phaseFlag = false;
01341 
01342     // Wait for the exit command.
01343     while (!diagDoneFlag) 
01344     {
01345         // Wait for the user command.
01346         command = fgetc(PC_HOST);
01347 
01348         // Decode and process the key stroke.
01349         switch (command) 
01350         {
01351             case 'e':
01352                 diagEraseFlash();
01353                 logInit();
01354                 break;
01355 
01356             case 's':
01357                 fprintf (PC_HOST, "Flash Electronic Signature 0x%02x\n\r", flashReadElectronicSignature());
01358                 break;
01359 
01360             // Toggle the system LED on/off.
01361             case 'l':
01362                 ledFlag = (ledFlag ? false : true);
01363                 output_bit (IO_LED, ledFlag);
01364                 break;
01365 
01366             // Display the help menu.
01367             case 'h':
01368             case 'H':
01369             case '?':
01370                 diagMenu();
01371                 break;
01372 
01373             case 'r':
01374                 diagReadFlash();
01375                 break;
01376 
01377             // Change the carrier frequency in 100Hz steps.
01378             case 'f':
01379                 freqHz -= 100;
01380                 ddsSetFreq (freqHz);
01381 
01382                 // Display the new frequency.
01383                 showSettingsFlag = true;
01384                 break;
01385 
01386             case 'F':
01387                 freqHz += 100;
01388                 ddsSetFreq (freqHz);
01389 
01390                 // Display the new frequency.
01391                 showSettingsFlag = true;
01392                 break;
01393 
01394             // Change the carrier frequency in 10KHz steps.
01395             case 'c':
01396                 freqHz -= 10000;
01397                 ddsSetFreq (freqHz);
01398 
01399                 // Display the new frequency.
01400                 showSettingsFlag = true;
01401                 break;
01402 
01403             case 'C':
01404                 freqHz += 10000;
01405                 ddsSetFreq (freqHz);
01406 
01407                 // Display the new frequency.
01408                 showSettingsFlag = true;
01409                 break;
01410 
01411             case 'a':
01412                 if (amplitude != 200)
01413                 {
01414                     amplitude += 5;
01415                     ddsSetAmplitude (amplitude);
01416 
01417                     // Display the new amplitude.
01418                     showSettingsFlag = true;
01419                 }
01420                 break;
01421 
01422             case 'A':
01423                 if (amplitude != 0)
01424                 {
01425                     amplitude -= 5;
01426                     ddsSetAmplitude (amplitude);
01427 
01428                     // Display the new amplitude.
01429                     showSettingsFlag = true;
01430                 }
01431                 break;
01432 
01433             case 'd':
01434                 if (lowBandFlag)
01435                 {
01436                     lowBandFlag = false;
01437                     freqHz = 50620000;
01438                 } else {
01439                     lowBandFlag = true;
01440                     freqHz = 14070450;
01441                 }   
01442 
01443                 // Display the new band setting.
01444                 showSettingsFlag = true; 
01445                 break;
01446                 
01447 
01448             // Toggle the PA on/off.
01449             case 'p':
01450                 paFlag = (paFlag ? false : true);
01451                 sysPAOutput (paFlag);
01452                 output_bit (IO_OSK, paFlag);
01453 
01454                 if (paFlag) 
01455                 {
01456                     ddsSetMode (DDS_MODE_PSK31);             
01457                     ddsSetFreq (freqHz);
01458                     ddsSetAmplitude (amplitude);
01459                     ddsPhase (phaseFlag);
01460                 } else
01461                     ddsSetMode (DDS_MODE_POWERDOWN);
01462 
01463                 break;
01464 
01465             case 'x':
01466                 diagDoneFlag = true;
01467                 break;
01468 
01469             case 't':
01470                 temperature = lm92GetTemp();
01471                 fprintf (PC_HOST, "%ld.%01ld degF\n\r", temperature / 10, temperature % 10);
01472                 break;
01473 
01474             case 'b':
01475                 disable_interrupts (GLOBAL);
01476                 fprintf (PC_HOST, "rebooting...\n\r\n\r");
01477                 reset_cpu();
01478                 break;
01479 
01480             case '1':
01481                 gpsPowerOn();
01482 
01483                 tcxo = 0x0000;
01484 
01485                 while (!kbhit(PC_HOST))
01486                 {
01487                     if (CCP_2 != tcxo)
01488                     {
01489                         fprintf (PC_HOST, "%ld %ld\n\r", CCP_2, CCP_2 - tcxo);
01490                         tcxo = CCP_2;
01491                     }
01492                 } // END while
01493 
01494                 gpsPowerOff();
01495                 break;
01496 
01497             case 'n':
01498                 cutdownFlag = (cutdownFlag ? false : true);
01499                 output_bit (IO_CUT_DOWN, cutdownFlag);
01500                 break;
01501 
01502             case 'u':
01503                 pumpFlag = (pumpFlag ? false : true);
01504                 output_bit (IO_BALLAST_PUMP, pumpFlag);
01505                 break;
01506 
01507             default:
01508                 fprintf (PC_HOST, "Invalid command.  (H)elp for menu.\n\r");
01509                 break;
01510         } // END switch
01511 
01512         // Display the results of any user requests or commands.
01513         if (showSettingsFlag) 
01514         {
01515             showSettingsFlag = false;
01516 
01517             fprintf (PC_HOST, "%02ld.%06ldMHz ", freqHz / 1000000, freqHz % 1000000);
01518             fprintf (PC_HOST, "%d.%01ddBc\n\r", amplitude / 10, amplitude % 10);
01519         } // END if
01520 
01521     } // END while
01522 
01523     // Let the user know we are done with this mode.
01524     fprintf (PC_HOST, "Exit diagnostic mode.\n\r");
01525 
01526     return;
01527 }
01528 
01544 bool_t flashIsWriteInProgress()
01545 {
01546     uint8_t status;
01547 
01548     output_low (IO_FLASH_CS);
01549 
01550     // Read Status Register (RDSR) flash command.
01551     flashSendByte (0x05);
01552 
01553     status = flashGetByte();
01554 
01555     output_high (IO_FLASH_CS);
01556 
01557     return (((status & 0x01) == 0x01) ? true : false);
01558 }
01559 
01567 void flashReadBlock(uint32_t address, uint8_t *block, uint16_t length)
01568 {
01569     uint16_t i;
01570     
01571     output_low (IO_FLASH_CS);
01572 
01573     // Read Data Byte(s) (READ) flash command.
01574     flashSendByte (0x03);
01575     flashSendAddress (address);
01576     
01577     for (i = 0; i < length; ++i)
01578         *block++ = flashGetByte();
01579     
01580     output_high (IO_FLASH_CS);
01581 }
01582 
01590 void flashWriteBlock(uint32_t address, uint8_t *block, uint8_t length)
01591 {
01592     uint8_t i;
01593 
01594     output_low (IO_FLASH_CS);
01595     // Write Enable (WREN) flash command.
01596     flashSendByte (0x06);
01597     output_high (IO_FLASH_CS);
01598     
01599     output_low (IO_FLASH_CS);
01600     // Page Program (PP) flash command.
01601     flashSendByte (0x02);
01602     flashSendAddress (address);
01603     
01604     for (i = 0; i < length; ++i) 
01605     {
01606         // Send each byte in the data block.
01607         flashSendByte (*block++);
01608 
01609         // Track the address in the flash device.
01610         ++address;
01611 
01612         // If we cross a page boundary (a page is 256 bytes) we need to stop and send the address again.
01613         if ((address & 0xff) == 0x00) 
01614         {
01615             output_high (IO_FLASH_CS);
01616 
01617             // Write this block of data.
01618             while (flashIsWriteInProgress());
01619 
01620             output_low (IO_FLASH_CS);
01621             // Write Enable (WREN) flash command.
01622             flashSendByte (0x06);
01623             output_high (IO_FLASH_CS);
01624 
01625             output_low (IO_FLASH_CS);
01626             // Page Program (PP) flash command.
01627             flashSendByte (0x02);
01628             flashSendAddress (address);
01629         } // END if
01630     } // END for    
01631 
01632     output_high (IO_FLASH_CS);
01633 
01634     // Wait for the final write operation to complete.
01635     while (flashIsWriteInProgress());
01636 }
01637 
01641 void flashErase()
01642 {
01643     output_low (IO_FLASH_CS);
01644 
01645     // Write Enable (WREN) flash command.
01646     flashSendByte (0x06);
01647     output_high (IO_FLASH_CS);
01648     
01649     output_low (IO_FLASH_CS);
01650     // Bulk Erase (BE) flash command.
01651     flashSendByte (0xc7);
01652 
01653     output_high (IO_FLASH_CS);
01654 
01655     while (flashIsWriteInProgress());
01656 }
01657 
01664 uint8_t flashReadElectronicSignature()
01665 {
01666     uint8_t electronicSignature;
01667 
01668     output_low (IO_FLASH_CS);
01669     flashSendByte (0xab);
01670     flashSendByte (0x00);
01671     flashSendByte (0x00);
01672     flashSendByte (0x00);
01673 
01674     electronicSignature = flashGetByte();
01675 
01676     output_high (IO_FLASH_CS);
01677 
01678     return electronicSignature;
01679 }
01680 
01688 uint8_t flashGetByte()
01689 {
01690     return spi_read(0x00);
01691 }
01692 
01696 void flashInit()
01697 {
01698     // I/O lines to control flash.
01699     output_high (IO_FLASH_CS);
01700 }
01701 
01709 void flashSendByte(uint8_t value)
01710 {
01711     spi_write (value);
01712 }
01713 
01721 void flashSendAddress(uint32_t address)
01722 {
01723     spi_write ((address >> 16) & 0xff);
01724     spi_write ((address >> 8) & 0xff);
01725     spi_write (address & 0xff);
01726 }
01727 
01738 
01739 #define GPS_BUFFER_SIZE 50
01740 
01742 enum GPS_PARSE_STATE_MACHINE 
01743 {
01745     GPS_START1,
01746 
01748     GPS_START2,
01749 
01751     GPS_COMMAND1,
01752 
01754     GPS_COMMAND2,
01755 
01757     GPS_READMESSAGE,
01758 
01760     GPS_CHECKSUMMESSAGE,
01761 
01763     GPS_EOMCR,
01764 
01766     GPS_EOMLF
01767 };
01768 
01770 uint8_t gpsIndex;
01771 
01773 GPS_PARSE_STATE_MACHINE gpsParseState;
01774 
01776 uint8_t gpsBuffer[GPS_BUFFER_SIZE]; 
01777 
01779 int32_t gpsPeakAltitude;
01780 
01782 uint8_t gpsChecksum;
01783 
01789 GPS_FIX_TYPE gpsGetFixType()
01790 {
01791     // The upper 3-bits determine the fix type.
01792     switch (gpsPosition.status & 0xe000) 
01793     {
01794         case 0xe000:
01795             return GPS_3D_FIX;
01796 
01797         case 0xc000:
01798             return GPS_2D_FIX;
01799     
01800         default:
01801             return GPS_NO_FIX;
01802     } // END switch
01803 }
01804 
01810 int32_t gpsGetPeakAltitude()
01811 {
01812     return gpsPeakAltitude;
01813 }
01814 
01818 void gpsInit()
01819 {
01820     // Initial parse state.
01821     gpsParseState = GPS_START1;
01822 
01823     // Assume we start at sea level.
01824     gpsPeakAltitude = 0;
01825 
01826     // Clear the structure that stores the position message.
01827     memset (&gpsPosition, 0, sizeof(GPSPOSITION_STRUCT));
01828 
01829     // Capture CCP2 on the rising edge of the GPS 1-PPS signal.
01830     setup_ccp2 (CCP_CAPTURE_RE);
01831 }
01832 
01839 bool_t gpsIsReady()
01840 {
01841     if (gpsPosition.updateFlag) 
01842     {
01843         gpsPosition.updateFlag = false;
01844         return true;
01845     } // END if
01846 
01847     return false;
01848 }
01849 
01858 uint8_t gpsNMEAChecksum (uint8_t *buffer, uint8_t length)
01859 {
01860     uint8_t i, checksum;
01861 
01862     checksum = 0;
01863 
01864     for (i = 0; i < length; ++i)
01865         checksum ^= buffer[i];
01866 
01867     return checksum;
01868 }
01869 
01876 bool_t gpsSetup()
01877 {
01878     uint8_t startTime, retryCount;
01879 
01880     // We wait 10 seconds for the GPS engine to respond to our message request.
01881     startTime = timeGetTicks();
01882     retryCount = 0;
01883 
01884     while (++retryCount < 10) 
01885     {
01886         // Read the serial FIFO and process the GPS messages.
01887         gpsUpdate();
01888 
01889         // If a GPS data set is available, then GPS is operational.
01890         if (gpsIsReady()) 
01891         {
01892             timeSetDutyCycle (TIME_DUTYCYCLE_20);
01893             return true;
01894         }
01895 
01896         if (timeGetTicks() > startTime) 
01897         {
01898             puts ("@@Hb\001\053\015\012");
01899             startTime += 10;
01900         } // END if
01901             
01902     } // END while
01903 
01904     return false;
01905 }
01906 
01910 void gpsParsePositionMessage()
01911 {
01912     // Convert the binary stream into data elements.  We will scale to the desired units
01913     // as the values are used.
01914     gpsPosition.updateFlag = true;
01915 
01916     gpsPosition.month = gpsBuffer[0];
01917     gpsPosition.day = gpsBuffer[1];
01918     gpsPosition.year = ((uint16_t) gpsBuffer[2] << 8) | gpsBuffer[3];
01919     gpsPosition.hours = gpsBuffer[4];
01920     gpsPosition.minutes = gpsBuffer[5];
01921     gpsPosition.seconds = gpsBuffer[6];
01922     gpsPosition.latitude = ((int32) gpsBuffer[11] << 24) | ((int32) gpsBuffer[12] << 16) | ((int32) gpsBuffer[13] << 8) | (int32) gpsBuffer[14];
01923     gpsPosition.longitude = ((int32) gpsBuffer[15] << 24) | ((int32) gpsBuffer[16] << 16) | ((int32) gpsBuffer[17] << 8) | gpsBuffer[18];
01924     gpsPosition.altitudeCM = ((int32) gpsBuffer[19] << 24) | ((int32) gpsBuffer[20] << 16) | ((int32) gpsBuffer[21] << 8) | gpsBuffer[22];
01925     gpsPosition.altitudeFeet = gpsPosition.altitudeCM * 100l / 3048l;
01926     gpsPosition.vSpeed = ((uint16_t) gpsBuffer[27] << 8) | gpsBuffer[28];
01927     gpsPosition.hSpeed = ((uint16_t) gpsBuffer[29] << 8) | gpsBuffer[30];
01928     gpsPosition.heading = ((uint16_t) gpsBuffer[31] << 8) | gpsBuffer[32];
01929     gpsPosition.dop = ((uint16_t) gpsBuffer[33] << 8) | gpsBuffer[34];
01930     gpsPosition.visibleSats = gpsBuffer[35];
01931     gpsPosition.trackedSats = gpsBuffer[36];
01932     gpsPosition.status = ((uint16_t) gpsBuffer[37] << 8) | gpsBuffer[38];
01933 
01934     // Update the peak altitude if we have a valid 3D fix.
01935     if (gpsGetFixType() == GPS_3D_FIX)
01936         if (gpsPosition.altitudeFeet > gpsPeakAltitude)
01937             gpsPeakAltitude = gpsPosition.altitudeFeet;
01938 }
01939 
01943 void gpsPowerOn()
01944 {
01945     // 3.0 VDC LDO control line.
01946     output_high (IO_GPS_PWR);
01947 
01948     // Enable the UART and the transmit line.
01949     SPEN = true;
01950 }
01951 
01955 void gpsPowerOff()
01956 {
01957     // Disable the UART and the transmit line.
01958     SPEN = false;
01959 
01960     // 3.0 VDC LDO control line.
01961     output_low (IO_GPS_PWR);
01962 }
01963 
01967 void gpsUpdate() 
01968 {
01969     uint8_t value;
01970 
01971     // This state machine handles each characters as it is read from the GPS serial port.
01972     // We are looking for the GPS mesage @@Hb ... C<CR><LF>
01973     while (serialHasData()) {
01974         // Get the character value.
01975         value = serialRead();
01976 
01977         // Process based on the state machine.
01978         switch (gpsParseState) 
01979         {
01980             case GPS_START1:
01981                 if (value == '@')
01982                     gpsParseState = GPS_START2;
01983                 break;
01984 
01985             case GPS_START2:
01986                 if (value == '@')
01987                     gpsParseState = GPS_COMMAND1;
01988                 else
01989                     gpsParseState = GPS_START1;
01990                 break;
01991 
01992             case GPS_COMMAND1:
01993                 if (value == 'H')
01994                     gpsParseState = GPS_COMMAND2;
01995                 else
01996                     gpsParseState = GPS_START1;
01997                 break;
01998 
01999             case GPS_COMMAND2:
02000                 if (value == 'b') 
02001                 {
02002                     gpsParseState = GPS_READMESSAGE;
02003                     gpsIndex = 0;
02004                     gpsChecksum = 0;
02005                     gpsChecksum ^= 'H';
02006                     gpsChecksum ^= 'b';
02007                 } else
02008                     gpsParseState = GPS_START1;
02009                 break;
02010 
02011             case GPS_READMESSAGE:
02012                 gpsChecksum ^= value;
02013                 gpsBuffer[gpsIndex++] = value;
02014 
02015                 if (gpsIndex == 47)
02016                     gpsParseState = GPS_CHECKSUMMESSAGE;
02017 
02018                 break;
02019 
02020             case GPS_CHECKSUMMESSAGE:
02021                 if (gpsChecksum == value)
02022                     gpsParseState = GPS_EOMCR;
02023                 else
02024                     gpsParseState = GPS_START1;
02025                 break;
02026 
02027             case GPS_EOMCR:
02028                 if (value == 13)
02029                     gpsParseState = GPS_EOMLF;
02030                 else
02031                     gpsParseState = GPS_START1;
02032                 break;
02033 
02034             case GPS_EOMLF:
02035                 // Once we have the last character, convert the binary message to something usable.
02036                 if (value == 10)
02037                     gpsParsePositionMessage();
02038 
02039                 gpsParseState = GPS_START1;
02040                 break;
02041         } // END switch
02042     } // END while
02043 }
02044 
02055 
02056 #define LOG_WRITE_BUFFER_SIZE 255
02057 
02059 uint32_t logAddress;
02060 
02062 uint8_t logBuffer[LOG_WRITE_BUFFER_SIZE];
02063 
02065 uint8_t logIndex;
02066 
02068 bool_t logDisableFlag;
02069 
02076 uint32_t logGetAddress()
02077 {
02078     return logAddress;
02079 }
02080 
02085 void logFlush()
02086 {
02087     if (logDisableFlag)
02088         return;
02089 
02090     // We only need to write if there is data.
02091     if (logIndex != 0) 
02092     {
02093         flashWriteBlock (logAddress, logBuffer, logIndex);
02094         logAddress += logIndex;
02095         logIndex = 0;
02096     } // END if
02097 }
02098 
02102 void logInit()
02103 {
02104     uint8_t buffer[8];
02105     bool_t endFound;
02106 
02107     // Flag that disable writes to flash.
02108     logDisableFlag = false;
02109 
02110     fprintf (PC_HOST, "Searching for end of flash log...");
02111 
02112     logAddress = 0x0000;
02113     endFound = false;
02114 
02115     // Read each logged data block from flash to determine how long it is.
02116     do 
02117     {
02118         // Read the data log entry type.
02119         flashReadBlock (logAddress, buffer, 1);
02120 
02121         // Based on the log entry type, we'll skip over the data contained in the entry.
02122         switch (buffer[0]) 
02123         {
02124             case LOG_BOOTED:
02125                 logAddress += 7;
02126                 break;
02127 
02128             case LOG_COORD:
02129                 logAddress += 26;
02130                 break;
02131 
02132             case LOG_TEMPERATURE_1:
02133             case LOG_TEMPERATURE_2:
02134                 logAddress += 3;
02135                 break;
02136 
02137             case LOG_VOLTAGE:
02138                 logAddress += 5;
02139                 break;
02140 
02141             case LOG_PUMP:
02142                 logAddress += 9;
02143                 break;
02144 
02145             case 0xff:
02146                 endFound = true;
02147                 break;
02148 
02149             default:
02150                 ++logAddress;
02151         } // END switch
02152     } while (logAddress < 0x100000 && !endFound);
02153 
02154     fprintf (PC_HOST, "done.\n\rLog contains %ld bytes.\n\r", logAddress);
02155 
02156     logIndex = 0;
02157 }
02158 
02165 void logSetDisableFlag (bool_t disableFlag)
02166 {
02167     logDisableFlag = disableFlag;
02168 }
02169 
02175 void logType (LOG_TYPE type)
02176 {
02177     // Only add the new entry if there is space.
02178     if (logAddress >= 0x100000)
02179         return;
02180 
02181     // Write the old entry first.
02182     logFlush();
02183 
02184     // Save the type and set the log buffer pointer.
02185     logBuffer[logIndex++] = type;
02186 }
02187 
02193 void logUint8 (uint8_t value)
02194 {
02195     logBuffer[logIndex++] = value;
02196 }
02197 
02203 void logInt16 (int16_t value)
02204 {
02205     logBuffer[logIndex++] = (value >> 8) & 0xff;
02206     logBuffer[logIndex++] = value & 0xff;
02207 }
02208 
02214 void logUint16 (uint16_t value)
02215 {
02216     logBuffer[logIndex++] = (value >> 8) & 0xff;
02217     logBuffer[logIndex++] = value & 0xff;
02218 }
02219 
02225 void logInt32 (int32_t value)
02226 {
02227     logBuffer[logIndex++] = (value >> 24) & 0xff;
02228     logBuffer[logIndex++] = (value >> 16) & 0xff;
02229     logBuffer[logIndex++] = (value >> 8) & 0xff;
02230     logBuffer[logIndex++] = value & 0xff;
02231 }
02232 
02243 #use i2c (master, scl=PIN_B5, sda=PIN_B1)
02244 
02250 int16_t lm92GetTemp()
02251 {
02252     int16_t value;
02253     int32_t temp;
02254 
02255     // Read the temperature register value.
02256     i2c_start();
02257     i2c_write(0x97);
02258     value = ((int16_t) i2c_read() << 8);
02259     value = value | ((int16_t) i2c_read() & 0x00f8);
02260     i2c_stop();
02261 
02262     //  LM92 register   0.0625degC/bit   9   10     9
02263     //  ------------- * -------------- * - * -- =  -- + 320
02264     //        8                          5         64
02265 
02266     // Convert to degrees F.
02267     temp = (int32_t) value;
02268     temp = ((temp * 9l) / 64l) + 320;
02269     
02270     return (int16_t) temp;
02271 }
02272 
02282 const uint16_t PSK31_VARICODE[] = 
02283 {
02284     0xAAC0, // ASCII =   0  1010101011
02285     0xB6C0, // ASCII =   1  1011011011
02286     0xBB40, // ASCII =   2  1011101101
02287     0xDDC0, // ASCII =   3  1101110111
02288     0xBAC0, // ASCII =   4  1011101011
02289     0xD7C0, // ASCII =   5  1101011111
02290     0xBBC0, // ASCII =   6  1011101111
02291     0xBF40, // ASCII =   7  1011111101
02292     0xBFC0, // ASCII =   8  1011111111
02293     0xEF00, // ASCII =   9  11101111
02294     0xE800, // ASCII =  10  11101
02295     0xDBC0, // ASCII =  11  1101101111
02296     0xB740, // ASCII =  12  1011011101
02297     0xF800, // ASCII =  13  11111
02298     0xDD40, // ASCII =  14  1101110101
02299     0xEAC0, // ASCII =  15  1110101011
02300     0xBDC0, // ASCII =  16  1011110111
02301     0xBD40, // ASCII =  17  1011110101
02302     0xEB40, // ASCII =  18  1110101101
02303     0xEBC0, // ASCII =  19  1110101111
02304     0xD6C0, // ASCII =  20  1101011011
02305     0xDAC0, // ASCII =  21  1101101011
02306     0xDB40, // ASCII =  22  1101101101
02307     0xD5C0, // ASCII =  23  1101010111
02308     0xDEC0, // ASCII =  24  1101111011
02309     0xDF40, // ASCII =  25  1101111101
02310     0xEDC0, // ASCII =  26  1110110111
02311     0xD540, // ASCII =  27  1101010101
02312     0xD740, // ASCII =  28  1101011101
02313     0xEEC0, // ASCII =  29  1110111011
02314     0xBEC0, // ASCII =  30  1011111011
02315     0xDFC0, // ASCII =  31  1101111111
02316     0x8000, // ASCII = ' '  1
02317     0xFF80, // ASCII = '!'  111111111
02318     0xAF80, // ASCII = '"'  101011111
02319     0xFA80, // ASCII = '#'  111110101
02320     0xED80, // ASCII = '$'  111011011
02321     0xB540, // ASCII = '%'  1011010101
02322     0xAEC0, // ASCII = '&'  1010111011
02323     0xBF80, // ASCII = '''  101111111
02324     0xFB00, // ASCII = '('  11111011
02325     0xF700, // ASCII = ')'  11110111
02326     0xB780, // ASCII = '*'  101101111
02327     0xEF80, // ASCII = '+'  111011111
02328     0xEA00, // ASCII = ','  1110101
02329     0xD400, // ASCII = '-'  110101
02330     0xAE00, // ASCII = '.'  1010111
02331     0xD780, // ASCII = '/'  110101111
02332     0xB700, // ASCII = '0'  10110111
02333     0xBD00, // ASCII = '1'  10111101
02334     0xED00, // ASCII = '2'  11101101
02335     0xFF00, // ASCII = '3'  11111111
02336     0xBB80, // ASCII = '4'  101110111
02337     0xAD80, // ASCII = '5'  101011011
02338     0xB580, // ASCII = '6'  101101011
02339     0xD680, // ASCII = '7'  110101101
02340     0xD580, // ASCII = '8'  110101011
02341     0xDB80, // ASCII = '9'  110110111
02342     0xF500, // ASCII = ':'  11110101
02343     0xDE80, // ASCII = ';'  110111101
02344     0xF680, // ASCII = '<'  111101101
02345     0xAA00, // ASCII = '='  1010101
02346     0xEB80, // ASCII = '>'  111010111
02347     0xABC0, // ASCII = '?'  1010101111
02348     0xAF40, // ASCII = '@'  1010111101
02349     0xFA00, // ASCII = 'A'  1111101
02350     0xEB00, // ASCII = 'B'  11101011
02351     0xAD00, // ASCII = 'C'  10101101
02352     0xB500, // ASCII = 'D'  10110101
02353     0xEE00, // ASCII = 'E'  1110111
02354     0xDB00, // ASCII = 'F'  11011011
02355     0xFD00, // ASCII = 'G'  11111101
02356     0xAA80, // ASCII = 'H'  101010101
02357     0xFE00, // ASCII = 'I'  1111111
02358     0xFE80, // ASCII = 'J'  111111101
02359     0xBE80, // ASCII = 'K'  101111101
02360     0xD700, // ASCII = 'L'  11010111
02361     0xBB00, // ASCII = 'M'  10111011
02362     0xDD00, // ASCII = 'N'  11011101
02363     0xAB00, // ASCII = 'O'  10101011
02364     0xD500, // ASCII = 'P'  11010101
02365     0xEE80, // ASCII = 'Q'  111011101
02366     0xAF00, // ASCII = 'R'  10101111
02367     0xDE00, // ASCII = 'S'  1101111
02368     0xDA00, // ASCII = 'T'  1101101
02369     0xAB80, // ASCII = 'U'  101010111
02370     0xDA80, // ASCII = 'V'  110110101
02371     0xAE80, // ASCII = 'W'  101011101
02372     0xBA80, // ASCII = 'X'  101110101
02373     0xBD80, // ASCII = 'Y'  101111011
02374     0xAB40, // ASCII = 'Z'  1010101101
02375     0xFB80, // ASCII = '['  1111101110
02376     0xF780, // ASCII = '\'  111101111
02377     0xFD80, // ASCII = ']'  111111011
02378     0xAFC0, // ASCII = '^'  1010111111
02379     0xB680, // ASCII = '_'  101101101
02380     0xB7C0, // ASCII = '`'  1011011111
02381     0xB000, // ASCII = 'a'  1011
02382     0xBE00, // ASCII = 'b'  1011111
02383     0xBC00, // ASCII = 'c'  101111
02384     0xB400, // ASCII = 'd'  101101
02385     0xC000, // ASCII = 'e'  11
02386     0xF400, // ASCII = 'f'  111101
02387     0xB600, // ASCII = 'g'  1011011
02388     0xAC00, // ASCII = 'h'  101011
02389     0xD000, // ASCII = 'i'  1101
02390     0xF580, // ASCII = 'j'  111101011
02391     0xBF00, // ASCII = 'k'  10111111
02392     0xD800, // ASCII = 'l'  11011
02393     0xEC00, // ASCII = 'm'  111011
02394     0xF000, // ASCII = 'n'  1111
02395     0xE000, // ASCII = 'o'  111
02396     0xFC00, // ASCII = 'p'  111111
02397     0xDF80, // ASCII = 'q'  110111111
02398     0xA800, // ASCII = 'r'  10101
02399     0xB800, // ASCII = 's'  10111
02400     0xA000, // ASCII = 't'  101
02401     0xDC00, // ASCII = 'u'  110111
02402     0xF600, // ASCII = 'v'  1111011
02403     0xD600, // ASCII = 'w'  1101011
02404     0xDF00, // ASCII = 'x'  11011111
02405     0xBA00, // ASCII = 'y'  1011101
02406     0xEA80, // ASCII = 'z'  111010101
02407     0xADC0, // ASCII = '{'  1010110111
02408     0xDD80, // ASCII = '|'  110111011
02409     0xAD40, // ASCII = '}'  1010110101
02410     0xB5C0, // ASCII = '~'  1011010111
02411     0xED40  // ASCII = 127  1110110101
02412 };
02413 
02415 #define PSK_MAX_PACKET 160
02416 
02418 enum PSK_MODE
02419 {
02421     PSK_WAIT_MSG,
02422 
02424     PSK_TX_SYNC,
02425 
02427     PSK_TX_MESSAGE,
02428 
02430     PSK_TX_END
02431 };
02432 
02434 #define PSK31_TIMESLOT 0
02435 
02437 #define PSK_SYNC_LENGTH 32
02438 
02440 #define PSK_END_LENGTH 8
02441 
02443 const uint32_t PSK31_FREQ_LIST[] = { 14070450, 14070450, 14070450 };
02444 const uint16_t PSK31_AMP_LIST[] = { 105, 105, 105 };
02445 
02447 uint8_t pskCount;
02448 
02450 uint16_t pskData;
02451 
02453 bool_t pskPhase;
02454 
02456 char pskBuffer[PSK_MAX_PACKET];
02457 
02459 PSK_MODE pskMode;
02460 
02462 uint8_t pskLastBits;
02463 
02465 uint8_t pskIndex;
02466 
02468 bool_t pskMessageDoneFlag;
02469 
02474 bool_t psk31CreateDataPacket()
02475 {
02476     int32_t temp;
02477     int16_t temperature;
02478     uint32_t coord, coordMin;
02479 
02480     // Record the temperature pre-transmit.
02481     temperature = lm92GetTemp();
02482 
02483     if (temperature == 0x13f)
02484         temperature = lm92GetTemp();
02485 
02486     logType (LOG_TEMPERATURE_1);
02487     logInt16 (temperature);
02488 
02489     // Line 1 - Header
02490     printf (psk31TxByte, "\n\n\nBalloon QSL www.kd7lmo.net\n");
02491     
02492     // Line 2 - Data with units.
02493     printf (psk31TxByte, "%02d%02dutc ", gpsPosition.hours, gpsPosition.minutes);
02494 
02495     // Altitude in feet.
02496     if (gpsPosition.altitudeFeet > 1000)
02497         printf (psk31TxByte, "%ld,", gpsPosition.altitudeFeet / 1000);
02498 
02499     printf (psk31TxByte, "%03ldft ", gpsPosition.altitudeFeet % 1000);
02500 
02501     // Latitude value.
02502     coord = gpsPosition.latitude;
02503 
02504     if (gpsPosition.latitude < 0) 
02505     {
02506         coord = gpsPosition.latitude * -1;
02507         printf (psk31TxByte, "S");
02508     } else {
02509         coord = gpsPosition.latitude;
02510         printf (psk31TxByte, "N");
02511     }
02512 
02513     coordMin = (coord % 3600000) / 600;
02514     printf (psk31TxByte, "%02ldd%02ld.%02ldm ", (uint32_t) (coord / 3600000), (uint32_t) (coordMin / 100), (uint32_t) (coordMin % 100));
02515 
02516     // Longitude value.
02517     if (gpsPosition.longitude < 0) 
02518     {
02519         coord = gpsPosition.longitude * - 1;
02520         printf (psk31TxByte, "W");
02521     } else {
02522         coord = gpsPosition.longitude;
02523         printf (psk31TxByte, "E");
02524     }
02525 
02526     coordMin = (coord % 3600000) / 600;
02527     printf (psk31TxByte, "%03ldd%02ld.%02ldm ", (uint32_t) (coord / 3600000), (uint32_t) (coordMin / 100), (uint32_t) (coordMin % 100));
02528 
02529     // Speed MPH and heading.
02530     temp = (int32_t) gpsPosition.hSpeed * 500 / 22352;
02531 
02532     printf (psk31TxByte, "%ldmph@%ldd ", temp, gpsPosition.heading / 10);
02533 
02534     printf (psk31TxByte, "%ld.%lddop ", gpsPosition.dop / 10, gpsPosition.dop % 10);
02535 
02536     printf (psk31TxByte, "%ld.%ldF ", temperature / 10, abs(temperature % 10));
02537 
02538     printf (psk31TxByte, "%ldp ", ballastGetPumpCount());
02539 
02540     if (cutDownIsActivate())
02541         printf (psk31TxByte, "*");
02542 
02543     printf (psk31TxByte, "\n");
02544 
02545     // Line 3 - Header / ident
02546     printf (psk31TxByte, "QSL www.kd7lmo.net de AC7ZT\n");
02547 
02548     // End of message line feeds.
02549     printf (psk31TxByte, "\n\n\n");
02550 
02551     // NULL terminate the string.
02552     psk31TxNull();
02553     
02554     return true;
02555 }
02556 
02560 void psk31Init()
02561 {
02562     pskCount = 0;
02563     pskData = 0x0000;
02564     pskIndex = 0;
02565     pskMode = PSK_WAIT_MSG;
02566     pskPhase = false;
02567     pskLastBits = 0x00;
02568     pskMessageDoneFlag = false;
02569 }
02570 
02576 bool_t psk31IsFree()
02577 {
02578     if (pskMode == PSK_WAIT_MSG)
02579         return true;
02580 
02581     return false;
02582 }
02583 
02587 void psk31TimeUpdate()
02588 {
02589     // If we are waiting for a message, just return.
02590     if (pskMode == PSK_WAIT_MSG)
02591         return;
02592 
02593     // If our next bit is 0 (zero), ramp down the carrier.
02594     if (pskCount == 15)
02595         if ((pskData & 0x8000) == 0x0000)
02596             output_low (IO_OSK);
02597 
02598     // Every 32mS process the next bit.
02599     if (++pskCount == 32) 
02600     {
02601         pskCount = 0;
02602 
02603         switch (pskMode) {
02604             case PSK_TX_SYNC:
02605                 // Just toggle the phase during the sync sequence.
02606                 if (pskPhase)
02607                     pskPhase = false;
02608                 else
02609                     pskPhase = true;
02610 
02611                 ddsPhase (pskPhase);
02612 
02613                 // After we send the start sequence, send the message.
02614                 if (--pskIndex == 0) 
02615                 {
02616                     pskMode = PSK_TX_MESSAGE;
02617                     pskIndex = 1;
02618                     pskData = PSK31_VARICODE[pskBuffer[0]];
02619                     pskLastBits = 0x0f;
02620                 } // END if
02621 
02622                 // Ramp the carrier back on.
02623                 output_high (IO_OSK);
02624 
02625                 break;
02626 
02627             case PSK_TX_MESSAGE:
02628                 // Keep track of the last 4 bits we transmitted.
02629                 pskLastBits = (pskLastBits << 1) & 0x0f;
02630 
02631                 // If the data bit is a zero, toggle the phase.
02632                 if ((pskData & 0x8000) == 0x0000) 
02633                 {
02634                     if (pskPhase)
02635                         pskPhase = false;
02636                     else
02637                         pskPhase = true;
02638 
02639                     ddsPhase (pskPhase);
02640                 } else
02641                     pskLastBits |= 0x01;
02642 
02643                 // Shift to the next bit.
02644                 pskData = pskData << 1;
02645 
02646                 // If the last 2 bits we sent were 0, then get the next byte.
02647                 if ((pskLastBits & 0x0c) == 0x00)
02648                     // Stop when we find the NULL character.
02649                     if (pskBuffer[pskIndex] == 0) 
02650                     {
02651                         pskIndex = PSK_END_LENGTH;
02652                         pskMode = PSK_TX_END;
02653                         pskData = 0x0000;
02654                     } else {
02655                         // Get the next character in the buffer.
02656                         pskData = PSK31_VARICODE[pskBuffer[pskIndex++]];
02657 
02658                         // Reset the last bits shift register.
02659                         pskLastBits = 0x0f;
02660                     } // END if-else
02661 
02662                 output_high (IO_OSK);
02663             
02664                 break;
02665 
02666             case PSK_TX_END:
02667                 // Just toggle the phase during the end sequence.
02668                 if (pskPhase)
02669                     pskPhase = false;
02670                 else
02671                     pskPhase = true;
02672 
02673                 ddsPhase (pskPhase);
02674 
02675                 if (--pskIndex == 0) 
02676                 {
02677                     // Turn off the carrier.
02678                     output_low (IO_OSK);
02679 
02680                     // Turn off the PA.
02681                     sysPAOutput (false);
02682 
02683                     ddsSetMode (DDS_MODE_POWERDOWN);
02684 
02685                     pskMessageDoneFlag = true;
02686 
02687                     // We are ready for a new mesasge.
02688                     pskMode = PSK_WAIT_MSG;
02689 
02690                     // Enable access to the flash that shares the DDS SPI port.
02691                     logSetDisableFlag (false);
02692                 } else
02693                     output_high (IO_OSK);
02694 
02695                 break;
02696         } // END switch
02697     } // END if
02698 }
02699 
02707 void psk31TxPacket(uint8_t minutes)
02708 {
02709     // We can't create a packet if one is already in progress.
02710     if (pskMode != PSK_WAIT_MSG || !tncIsFree())
02711         return;
02712 
02713     // Only transmit every 6 minutes
02714     if ((minutes % 6) != 0)
02715         return;
02716 
02717     // Disable access to the flash that shares the SPI port.
02718     logSetDisableFlag (true);
02719 
02720     // Set the pointer to the start of the buffer.
02721     pskIndex = 0;
02722         
02723     // If the packet generations fails, display a warning message.
02724     if (!psk31CreateDataPacket()) 
02725     {
02726         pskIndex = 0;
02727         printf (psk31TxByte, "Ballooon QSL www.kd7lmo.net * Unable to generate telemetry\n\n");
02728         psk31TxNull();
02729     }
02730     
02731     // Select the PSK-31 real-time clock mode.
02732     timeSetMode (TIME_MODE_PSK31);
02733     
02734     // Configure the DDS for PSK-31 mode.
02735     ddsSetMode (DDS_MODE_PSK31);
02736     
02737     // Set the DDS frequency based on the time schedule that repeats every 6 minutes.
02738     ddsSetFreq (PSK31_FREQ_LIST[minutes % 3]);
02739     ddsSetAmplitude (PSK31_AMP_LIST[minutes % 3]);
02740     
02741     // Turn on the PA.
02742     sysPAOutput (true);
02743 
02744     // Prepare the variables that are used in the real-time clock interrupt.
02745     pskIndex = PSK_SYNC_LENGTH;
02746     pskCount = 0;
02747     pskData = 0x0000;
02748     pskMode = PSK_TX_SYNC;
02749 }
02750 
02758 void psk31TxByte (uint8_t value)
02759 {
02760     if (pskIndex == PSK_MAX_PACKET)
02761         return;
02762 
02763     pskBuffer[pskIndex++] = value;
02764 }
02765 
02769 void psk31TxString (char *string, uint8_t length)
02770 {
02771     while (length-- != 0)
02772         psk31TxByte (*string++);
02773 }
02774 
02775 void psk31TxNull ()
02776 {
02777     psk31TxByte (0x00);
02778 }
02779 
02780 bool_t psk31IsMessageDone()
02781 {
02782     if (pskMessageDoneFlag)
02783     {
02784         pskMessageDoneFlag = false;
02785         return true;
02786     }
02787 
02788     return false;
02789 }
02790 
02801 
02802 #define SERIAL_BUFFER_SIZE 64
02803 
02805 #define SERIAL_BUFFER_MASK 0x3f
02806 
02808 uint8_t serialHead;
02809 
02811 uint8_t serialTail;
02812 
02814 uint8_t serialBuffer[SERIAL_BUFFER_SIZE];
02815 
02821 bool_t serialHasData()
02822 {
02823     if (serialHead == serialTail)
02824         return false;
02825 
02826     return true;
02827 }
02828 
02832 void serialInit()
02833 {
02834     serialHead = 0;
02835     serialTail = 0;
02836 }
02837 
02843 uint8_t serialRead()
02844 {
02845     uint8_t value;
02846 
02847     // Make sure we have something to return.
02848     if (serialHead == serialTail)
02849         return 0;
02850 
02851     // Save the value.
02852     value = serialBuffer[serialTail];
02853 
02854     // Update the pointer.
02855     serialTail = (serialTail + 1) & SERIAL_BUFFER_MASK;
02856 
02857     return value;
02858 }
02859 
02863 void serialUpdate()
02864 {
02865     // If there isn't a character in the PIC buffer, just leave.
02866     while (kbhit()) 
02867     {
02868         // Save the value in the FIFO.
02869         serialBuffer[serialHead] = getc();
02870 
02871         // Move the pointer to the next open space.
02872         serialHead = (serialHead + 1) & SERIAL_BUFFER_MASK;
02873     }
02874 }
02875 
02889 void sysLogGPSData()
02890 {
02891     // Log the data.
02892     logType (LOG_COORD);
02893     logUint8 (gpsPosition.hours);
02894     logUint8 (gpsPosition.minutes);
02895     logUint8 (gpsPosition.seconds);
02896     logInt32 (gpsPosition.latitude);
02897     logInt32 (gpsPosition.longitude);
02898     logInt32 (gpsPosition.altitudeCM);
02899 
02900     logUint16 (gpsPosition.vSpeed);
02901     logUint16 (gpsPosition.hSpeed);
02902     logUint16 (gpsPosition.heading);
02903 
02904     logUint16 (gpsPosition.status);
02905 
02906     logUint8 ((uint8_t) (gpsPosition.dop & 0xff));
02907     logUint8 ((uint8_t) ((gpsPosition.visibleSats << 4) | gpsPosition.trackedSats));
02908 }
02909 
02920 uint16_t sysCRC16(uint8_t *buffer, uint8_t length, uint16_t crc)
02921 {
02922     uint8_t i, bit, value;
02923 
02924     for (i = 0; i < length; ++i) 
02925     {
02926         value = buffer[i];
02927 
02928         for (bit = 0; bit < 8; ++bit) {
02929             crc ^= (value & 0x01);
02930             crc = ( crc & 0x01 ) ? ( crc >> 1 ) ^ 0x8408 : ( crc >> 1 );
02931             value = value >> 1;
02932         } // END for
02933     } // END for
02934 
02935     return crc ^ 0xffff;
02936 }
02937 
02943 inline void sysPAOutput (bool_t state)
02944 {
02945     if (state)
02946         output_low (IO_PA);
02947     else
02948         output_high (IO_PA);
02949 }
02950 
02961 
02962 uint8_t timeTicks;
02963 
02965 uint16_t timeInterruptCount;
02966 
02968 uint8_t time100ms;
02969 
02971 uint8_t timeSeconds;
02972 
02974 uint8_t timeMinutes;
02975 
02977 uint8_t timeHours;
02978 
02980 uint8_t timeDutyCycle;
02981 
02983 uint16_t timeCompare;
02984 
02986 uint16_t timeRate;
02987 
02989 bool_t timeUpdateFlag;
02990 
02992 bool_t timeRunFlag;
02993 
02995 uint16_t timeInterruptCountRollOver;
02996 
02998 TIME_MODE timeMode;
02999 
03001 #define TIME_RATE_PSK31 4800
03002 #define TIME_RATE_APRS 500
03003 #define TIME_RATE_HF_APRS 16000
03004 
03006 #define TIME_ROLLOVER_PSK31 100
03007 #define TIME_ROLLOVER_APRS 960
03008 #define TIME_ROLLOVER_HF_APRS 30
03009 
03015 uint8_t timeGetTicks()
03016 {
03017     return timeTicks;
03018 }
03019 
03023 void timeInit()
03024 {
03025     timeTicks = 0;
03026     timeInterruptCount = 0;
03027     time100mS = 0;
03028     timeSeconds = 0;
03029     timeMinutes = 0;
03030     timeHours = 0;
03031     timeDutyCycle = TIME_DUTYCYCLE_70;
03032     timeCompare = TIME_RATE_APRS;
03033     timeUpdateFlag = false;
03034     timeRate = TIME_RATE_APRS;
03035     timeRunFlag = false;
03036     timeUpdateFlag = false;
03037     timeInterruptCountRollOver = TIME_ROLLOVER_APRS;
03038     timeMode = TIME_MODE_APRS;
03039     
03040     // Configure CCP1 to interrupt at 1mS for PSK31 or 833uS for 1200 baud APRS
03041     CCP_1 = timeRate;
03042     set_timer1(timeCompare);
03043     setup_ccp1( CCP_COMPARE_INT );
03044     setup_timer_1( T1_INTERNAL | T1_DIV_BY_1 );
03045 }
03046 
03052 uint8_t timeGetHours()
03053 {
03054     return timeHours;
03055 }
03056 
03062 uint8_t timeGetMinutes()
03063 {
03064     return timeMinutes;
03065 }
03066 
03072 void timeSetDutyCycle (uint8_t dutyCycle)
03073 {
03074     timeDutyCycle = dutyCycle;
03075 }
03076 
03081 void timeSetRunFlag()
03082 {
03083     timeRunFlag = true;
03084 }
03085 
03091 void timeSetMode (TIME_MODE mode)
03092 {
03093     // If we are already in the desired mode, we don't need to do anything.
03094     if (mode == timeMode)
03095         return;
03096         
03097     // Save the new mode.
03098     timeMode = mode;
03099     
03100     // Disable interrupts while we adjust the time information.
03101     disable_interrupts (INT_CCP1);
03102     
03103     switch (timeMode) {
03104         case TIME_MODE_APRS:
03105             timeRate = TIME_RATE_APRS;
03106             timeInterruptCountRollOver = TIME_ROLLOVER_APRS;
03107             break;
03108         
03109         case TIME_MODE_PSK31:
03110             timeRate = TIME_RATE_PSK31;
03111             timeInterruptCountRollOver = TIME_ROLLOVER_PSK31;
03112             break;
03113 
03114         case TIME_MODE_HF_APRS:
03115             timeRate = TIME_RATE_HF_APRS;
03116             timeInterruptCountRollOver = TIME_ROLLOVER_HF_APRS;
03117             break;
03118     } // END switch
03119     
03120     // If the current interrupt count is past the roller over state, move it back.
03121     // This means we will loose an interrupt period, but we don't really care.
03122     timeInterruptCount = timeInterruptCount % timeInterruptCountRollOver;
03123         
03124     // Restart the interrupts and we are back on-line.
03125     enable_interrupts (INT_CCP1);
03126 }
03127 
03128 // This function gets called every 1mS.
03129 #INT_CCP1
03130 void timeUpdate()
03131 {
03132     // Pin used to measure CPU load in interrupt.
03133     output_high (PIN_B1);
03134 
03135     // Setup the next interrupt for the operational mode.
03136     timeCompare += timeRate;
03137     CCP_1 = timeCompare;
03138 
03139     // Call the appropriate time routine.
03140     if (timeMode == TIME_MODE_PSK31)
03141         psk31TimeUpdate();
03142     else
03143         tncTimeUpdate();
03144 
03145     // Read the GPS serial port and save any incoming characters.
03146     serialUpdate();
03147 
03148     // Count the number of milliseconds required for the tenth second counter.
03149     if (++timeInterruptCount == timeInterruptCountRollOver) 
03150     {
03151         timeInterruptCount = 0;
03152 
03153         // This timer just ticks every 100mS and is used for general timing.
03154         ++timeTicks;
03155 
03156         // Roll the counter over every second.
03157         if (++time100mS == 10) 
03158         {
03159             time100mS = 0;
03160 
03161             // We set this flag true every second.
03162             timeUpdateFlag = true;
03163 
03164             // Maintain a Real Time Clock.
03165             if (timeRunFlag)
03166                 if (++timeSeconds == 60) 
03167                 {
03168                     timeSeconds = 0;
03169     
03170                     if (++timeMinutes == 60) 
03171                     {
03172                         timeMinutes = 0;
03173                         ++timeHours;
03174                     } // END if
03175                 } // END if timeMinutes
03176         } // END if time100mS
03177 
03178         // Flash the status LED at timeDutyCycle % per second.  We use the duty cycle for mode feedback.
03179         if (time100mS >= timeDutyCycle)
03180             output_low (IO_LED);
03181         else
03182             output_high (IO_LED);
03183     } // END if
03184 
03185     // Pin used to measure CPU load in interrupt.
03186     output_low (PIN_B1);
03187 }
03188 
03199 
03200 #define TNC_TX_DELAY 45
03201 
03203 #define TNC_TIMESLOT 55
03204 
03206 enum TNC_MODE
03207 {
03209     TNC_TX_READY,
03210 
03212     TNC_TX_SYNC,
03213 
03215     TNC_TX_HEADER,
03216 
03218     TNC_TX_DATA,
03219 
03221     TNC_TX_END
03222 };
03223 
03224 // The size of the TNC output buffer.
03225 #define TNC_BUFFER_SIZE 80
03226 
03227 // The dwell duration in bits at each idle test tone.
03228 #define TNC_DWELL_TIME 3600
03229 
03230 // The packet header.
03231 uint8_t TNC_AX25_HEADER[30] = 
03232 { 
03233     'A' << 1, 'P' << 1, 'R' << 1, 'S' << 1, ' ' << 1, ' ' << 1, 0x60, \
03234     'K' << 1, 'D' << 1, '7' << 1, 'L' << 1, 'M' << 1, 'O' << 1, 0x76, \
03235     'G' << 1, 'A' << 1, 'T' << 1, 'E' << 1, ' ' << 1, ' ' << 1, 0x60, \
03236     'W' << 1, 'I' << 1, 'D' << 1, 'E' << 1, '3' << 1, ' ' << 1, 0x67, \
03237     0x03, 0xf0 
03238 };
03239 
03240 uint8_t tncLastBit;
03241 uint8_t tncPacketType;
03242 
03244 TNC_MODE tncMode;
03245 
03247 uint8_t tncBitCount;
03248 
03250 uint8_t tncShift;
03251 
03253 uint8_t tncIndex;
03254 
03256 uint8_t tncLength;
03257 
03259 uint8_t tncBitStuff;
03260 
03262 uint8_t *tncBufferPnt;
03263 
03265 uint8_t tncBuffer[TNC_BUFFER_SIZE];
03266 
03267 // 1200 baud counter that determine which test signal to generate
03268 uint16_t tncTestCount;
03269 
03271 uint16_t timeNCO;
03272 
03274 uint16_t timeNCOFreq;
03275 
03277 uint8_t timeLowRateCount;
03278 
03279 void tncInit()
03280 {
03281     tncLastBit = 0;
03282     tncMode = TNC_TX_READY;
03283     tncTestCount = 0;
03284     tncPacketType = TNC_BOOT_MESSAGE;
03285     timeNCO = 0x00;
03286     timeLowRateCount = 0;
03287     timeNCOFreq = 0x2000;
03288 }
03289 
03295 bool_t tncIsFree()
03296 {
03297     if (tncMode == TNC_TX_READY)
03298         return true;
03299 
03300     return false;
03301 }
03302 
03303 // This ISR is called when the timer register matches the compare register.
03304 // The interrupt rate is programmed to 833uS or 1 bit time at 1200 baud.
03305 void tncTimeUpdate()
03306 {
03307     // If we are waiting for a message, just return.
03308     if (tncMode == TNC_TX_READY)
03309         return;
03310 
03311     // Set the DDS frequency.
03312     ddsSetFTW (freqTable[timeNCO >> 8]);
03313     
03314     // Adjust the NCO phase.
03315     timeNCO += timeNCOFreq;
03316     
03317     if (++timeLowRateCount == 8) 
03318     {
03319         timeLowRateCount = 0;
03320 
03321         // Set the A-FSK frequency.
03322         if (tncLastBit == 0x00)
03323             timeNCOFreq = 0x2000;
03324         else
03325             timeNCOFreq = 0x3aab;
03326 
03327         switch (tncMode) 
03328         {
03329             case TNC_TX_SYNC:
03330                 // The variable tncShift contains the lastest data byte.
03331                 // NRZI enocde the data stream.
03332                 if ((tncShift & 0x01) == 0x00)
03333                     if (tncLastBit == 0)
03334                         tncLastBit = 1;
03335                     else
03336                         tncLastBit = 0;
03337                         
03338                 // When the flag is done, determine if we need to send more or data.
03339                 if (++tncBitCount == 8) 
03340                 {
03341                     tncBitCount = 0;
03342                     tncShift = 0x7e;
03343     
03344                     // Once we transmit x mS of flags, send the data.
03345                     // txDelay bytes * 8 bits/byte * 833uS/bit = x mS
03346                     if (++tncIndex == TNC_TX_DELAY) 
03347                     {
03348                         tncIndex = 0;
03349                         tncShift = TNC_AX25_HEADER[0];
03350                         tncBitStuff = 0;
03351                         tncMode = TNC_TX_HEADER;
03352                     } // END if
03353                 } else
03354                     tncShift = tncShift >> 1;
03355                 break;
03356     
03357             case TNC_TX_HEADER:
03358                 // Determine if we have sent 5 ones in a row, if we have send a zero.
03359                 if (tncBitStuff == 0x1f) 
03360                 {
03361                     if (tncLastBit == 0)
03362                         tncLastBit = 1;
03363                     else
03364                         tncLastBit = 0;
03365     
03366                     tncBitStuff = 0x00;
03367                     return;
03368                 }    // END if
03369     
03370                 // The variable tncShift contains the lastest data byte.
03371                 // NRZI enocde the data stream.
03372                 if ((tncShift & 0x01) == 0x00)
03373                     if (tncLastBit == 0)
03374                         tncLastBit = 1;
03375                     else
03376                         tncLastBit = 0;
03377     
03378                 // Save the data stream so we can determine if bit stuffing is 
03379                 // required on the next bit time.
03380                 tncBitStuff = ((tncBitStuff << 1) | (tncShift & 0x01)) & 0x1f;
03381     
03382                 // If all the bits were shifted, get the next byte.
03383                 if (++tncBitCount == 8) 
03384                 {
03385                     tncBitCount = 0;
03386     
03387                     // After the header is sent, then send the data.
03388                     if (++tncIndex == sizeof(TNC_AX25_HEADER)) 
03389                     {
03390                         tncIndex = 0;
03391                         tncShift = tncBuffer[0];
03392                         tncMode = TNC_TX_DATA;
03393                     } else
03394                         tncShift = TNC_AX25_HEADER[tncIndex];
03395     
03396                 } else
03397                     tncShift = tncShift >> 1;
03398     
03399                 break;
03400     
03401             case TNC_TX_DATA:
03402                 // Determine if we have sent 5 ones in a row, if we have send a zero.
03403                 if (tncBitStuff == 0x1f) 
03404                 {
03405                     if (tncLastBit == 0)
03406                         tncLastBit = 1;
03407                     else
03408                         tncLastBit = 0;
03409     
03410                     tncBitStuff = 0x00;
03411                     return;
03412                 }    // END if
03413     
03414                 // The variable tncShift contains the lastest data byte.
03415                 // NRZI enocde the data stream.
03416                 if ((tncShift & 0x01) == 0x00)
03417                     if (tncLastBit == 0)
03418                         tncLastBit = 1;
03419                     else
03420                         tncLastBit = 0;
03421     
03422                 // Save the data stream so we can determine if bit stuffing is 
03423                 // required on the next bit time.
03424                 tncBitStuff = ((tncBitStuff << 1) | (tncShift & 0x01)) & 0x1f;
03425     
03426                 // If all the bits were shifted, get the next byte.
03427                 if (++tncBitCount == 8) 
03428                 {
03429                     tncBitCount = 0;
03430     
03431                     // If everything was sent, transmit closing flags.
03432                     if (++tncIndex == tncLength) 
03433                     {
03434                         tncIndex = 0;
03435                         tncShift = 0x7e;
03436                         tncMode = TNC_TX_END;
03437                     } else
03438                         tncShift = tncBuffer[tncIndex];
03439     
03440                 } else
03441                     tncShift = tncShift >> 1;
03442     
03443                 break;
03444     
03445             case TNC_TX_END:
03446                 // The variable tncShift contains the lastest data byte.
03447                 // NRZI enocde the data stream. 
03448                 if ((tncShift & 0x01) == 0x00)
03449                     if (tncLastBit == 0)
03450                         tncLastBit = 1;
03451                     else
03452                         tncLastBit = 0;
03453     
03454                 // If all the bits were shifted, get the next one.
03455                 if (++tncBitCount == 8) 
03456                 {
03457                     tncBitCount = 0;
03458                     tncShift = 0x7e;
03459         
03460                     // Transmit closing flags.
03461                     if (++tncIndex == 2) 
03462                     {
03463                         // Turn off the DDS and PA (PTT).
03464                         ddsPTT (false);
03465                         sysPAOutput (false);
03466                         ddsSetMode (DDS_MODE_POWERDOWN);
03467 
03468                         tncMode = TNC_TX_READY;
03469 
03470                         // Disable access to the flash that shares the SPI port.
03471                         logSetDisableFlag (false);
03472                         return;
03473                     } // END if
03474                 } else
03475                     tncShift = tncShift >> 1;
03476     
03477                 break;
03478         } // END switch
03479     } // END if
03480 }
03481 
03489 void tncTxByte (uint8_t value)
03490 {
03491     *tncBufferPnt++ = value;
03492     ++tncLength;
03493 }
03494 
03499 void tncNMEATime()
03500 {
03501     // UTC of position fix.
03502     printf (tncTxByte, "%02d%02d%02d,", gpsPosition.hours, gpsPosition.minutes, gpsPosition.seconds);
03503 }
03504 
03509 void tncNMEAFix()
03510 {
03511     uint8_t dirChar;
03512     uint32_t coord, coordMin;
03513 
03514     // Latitude value.
03515     coord = gpsPosition.latitude;
03516 
03517     if (gpsPosition.latitude < 0) 
03518     {
03519         coord = gpsPosition.latitude * -1;
03520         dirChar = 'S';
03521     } else {
03522         coord = gpsPosition.latitude;
03523         dirChar = 'N';
03524     }
03525 
03526     coordMin = (coord % 3600000) / 6;
03527     printf (tncTxByte, "%02ld%02ld.%04ld,%c,", (uint32_t) (coord / 3600000), (uint32_t) (coordMin / 10000), (uint32_t) (coordMin % 10000), dirChar);
03528 
03529 
03530     // Longitude value.
03531     if (gpsPosition.longitude < 0) {
03532         coord = gpsPosition.longitude * - 1;
03533         dirChar = 'W';
03534     } else {
03535         coord = gpsPosition.longitude;
03536         dirChar = 'E';
03537     }
03538 
03539     coordMin = (coord % 3600000) / 6;
03540     printf (tncTxByte, "%03ld%02ld.%04ld,%c,", (uint32_t) (coord / 3600000), (uint32_t) (coordMin / 10000), (uint32_t) (coordMin % 10000), dirChar);
03541 }
03542 
03547 void tncStatusPacket()
03548 {
03549     int16_t temperature;
03550 
03551     // Plain text telemetry.
03552     printf (tncTxByte, ">Balloon ");
03553     
03554     // Display the flight time.
03555     printf (tncTxByte, "%03U:%02U:%02U ", timeHours, timeMinutes, timeSeconds);
03556     
03557     // Altitude in feet.
03558     printf (tncTxByte, "%ld' ", gpsPosition.altitudeFeet);
03559     
03560     // GPS hdop or pdop
03561     printf (tncTxByte, "%lu.%lu", gpsPosition.dop / 10, gpsPosition.dop % 10);
03562 
03563     // The text 'pdop' for a 3D fix, 'hdop' for a 2D fix, and 'dop' for no fix.
03564     switch (gpsGetFixType()) 
03565     {
03566         case GPS_NO_FIX:
03567             printf (tncTxByte, "dop ");
03568             break;
03569 
03570         case GPS_2D_FIX:
03571             printf (tncTxByte, "hdop ");
03572             break;
03573 
03574         case GPS_3D_FIX:
03575             printf (tncTxByte, "pdop ");
03576             break;
03577     } // END switch
03578 
03579     // Number of satellites in the solution.
03580     printf (tncTxByte, "%utrk ", gpsPosition.trackedSats);
03581 
03582     // Internal temperature.
03583     temperature = lm92GetTemp();
03584 
03585     printf (tncTxByte, "%ld.%ldF ", temperature / 10, abs(temperature % 10));
03586     
03587     // Print web address link.
03588     printf (tncTxByte, "QSL www.kd7lmo.net");
03589 }  
03590 
03595 void tncGPGGAPacket()
03596 {
03597     // Generate the GPGGA message.
03598     printf (tncTxByte, "$GPGGA,");
03599 
03600     // Standard NMEA time.
03601     tncNMEATime();
03602 
03603     // Standard NMEA-0183 latitude/longitude.
03604     tncNMEAFix();
03605 
03606     // GPS status where 0: not available, 1: available
03607     if (gpsGetFixType() != GPS_NO_FIX)
03608         printf (tncTxByte, "1,");
03609     else
03610         printf (tncTxByte, "0,");
03611 
03612     // Number of visible birds.
03613     printf (tncTxByte, "%02d,", gpsPosition.trackedSats);
03614 
03615     // DOP
03616     printf (tncTxByte, "%ld.%01ld,", gpsPosition.dop / 10, gpsPosition.dop % 10);
03617 
03618     // Altitude in meters.
03619     printf (tncTxByte, "%ld.%02ld,M,,M,,", (int32_t) (gpsPosition.altitudeCM / 100l), (int32_t) (gpsPosition.altitudeCM % 100));
03620 
03621     // Checksum, we add 1 to skip over the $ character.
03622     printf (tncTxByte, "*%02X", gpsNMEAChecksum(tncBuffer + 1, tncLength - 1));
03623 }
03624 
03629 void tncGPRMCPacket()
03630 {
03631     uint32_t temp;
03632 
03633     // Generate the GPRMC message.
03634     printf (tncTxByte, "$GPRMC,");
03635 
03636     // Standard NMEA time.
03637     tncNMEATime();
03638 
03639     // GPS status.
03640     if (gpsGetFixType() != GPS_NO_FIX)
03641         printf (tncTxByte, "A,");
03642     else
03643         printf (tncTxByte, "V,");
03644 
03645     // Standard NMEA-0183 latitude/longitude.
03646     tncNMEAFix();
03647 
03648     // Speed knots and heading.
03649     temp = (int32_t) gpsPosition.hSpeed * 75000 / 385826;
03650     printf (tncTxByte, "%ld.%ld,%ld.%ld,", (int16_t) (temp / 10), (int16_t) (temp % 10), gpsPosition.heading / 10, gpsPosition.heading % 10);
03651 
03652     // Date
03653     printf (tncTxByte, "%02d%02d%02ld,,", gpsPosition.day, gpsPosition.month, gpsPosition.year % 100);
03654 
03655     // Checksum, skip over the $ character.
03656     printf (tncTxByte, "*%02X", gpsNMEAChecksum(tncBuffer + 1, tncLength - 1));
03657 }
03658 
03663 void tncTxPacket(TNC_PACKET_TYPE tncPacketType)
03664 {
03665     uint16_t crc;
03666 
03667     // Only transmit if there is not another message in progress and PSK 31 isn't using the hardware.
03668     if (tncMode != TNC_TX_READY || !psk31IsFree())
03669         return;
03670 
03671     // Disable access to the flash that shares the SPI port.
03672     logSetDisableFlag (true);
03673 
03674     // Set a pointer to our TNC output buffer.
03675     tncBufferPnt = tncBuffer;
03676 
03677     // Set the message length counter.
03678     tncLength = 0;
03679 
03680     // Determine the contents of the packet.
03681     switch (tncPacketType) 
03682     {
03683         case TNC_BOOT_MESSAGE:
03684             printf (tncTxByte, ">ANSR PSK-31/APRS Beacon - V1.07");
03685             break;
03686 
03687         case TNC_STATUS:
03688             tncStatusPacket();
03689             break;
03690 
03691         case TNC_GGA:
03692             tncGPGGAPacket();
03693             break;
03694 
03695         case TNC_RMC:
03696             tncGPRMCPacket();
03697             break;
03698     }
03699 
03700     // Add the end of message character.
03701     printf (tncTxByte, "\015");
03702 
03703     // Calculate the CRC for the header and message.
03704     crc = sysCRC16(TNC_AX25_HEADER, sizeof(TNC_AX25_HEADER), 0xffff);
03705     crc = sysCRC16(tncBuffer, tncLength, crc ^ 0xffff);
03706 
03707     // Save the CRC in the message.
03708     *tncBufferPnt++ = crc & 0xff;
03709     *tncBufferPnt = (crc >> 8) & 0xff;
03710 
03711     // Update the length to include the CRC bytes.
03712     tncLength += 2;
03713 
03714     // Select the APRS real-time clock mode.
03715     timeSetMode (TIME_MODE_APRS);
03716     
03717     // Configure the DDS for APRS mode.
03718     ddsSetMode (DDS_MODE_APRS);
03719 
03720     // Set for maximum output level.  Yes, 10.5dBC on the DDS is correct since the PA operates in compression above HF.
03721     ddsSetAmplitude (105);
03722 
03723     // Prepare the variables that are used in the real-time clock interrupt.
03724     tncBitCount = 0;
03725     tncShift = 0x7e;
03726     tncLastBit = 0;
03727     tncIndex = 0;
03728     tncMode = TNC_TX_SYNC;
03729 
03730     // Turn on the DSS and PA (PTT).
03731     ddsPTT (true);
03732     sysPAOutput (true);
03733 }
03734 
03737 // This is where we go after reset.
03738 void main()
03739 {
03740     uint8_t utcSeconds, utcMinutes, lockLostCounter;
03741 
03742     // Set the initial output state before we configure the output direction.
03743     output_low (IO_GPS_PWR);
03744     output_high (IO_LED);
03745 
03746     output_low (IO_CUT_DOWN);
03747     output_high (IO_PA);
03748 
03749     // Disable the ADC so we can use PORT A digital I/O.
03750     setup_adc_ports( NO_ANALOGS );
03751 
03752     // Configure the I/O ports.
03753     set_tris_a (0x00);
03754     set_tris_b (0x62);
03755     set_tris_c (0x92);
03756 
03757     // Setup the subsystems.
03758     ballastInit();
03759     cutDownInit();
03760     gpsInit();
03761     timeInit();
03762     psk31Init();
03763     serialInit();
03764     tncInit();
03765 
03766     // Wait for the power converter to stabilize and the subsystems to reset.
03767     delay_ms (400);
03768 
03769     // Program the DDS.
03770     ddsInit();
03771 
03772     // Finally setup the log.  We do this after the DDS because the SPI port gets set there.
03773     logInit();
03774 
03775     // Turn off the LED just as we enable the interrupts.
03776     output_low (IO_LED);
03777 
03778     // Check for the diagnostics plug, otherwise we'll continue to boot.
03779     diagPort();
03780 
03781     // Setup our interrupts.
03782     enable_interrupts(GLOBAL);
03783     enable_interrupts(INT_CCP1);
03784 
03785     // Turn on the GPS engine.
03786     output_high (IO_GPS_PWR);
03787 
03788     // Allow the GPS engine to boot.
03789     delay_ms (100);
03790 
03791     // Initialize the GPS engine.
03792     while (!gpsSetup());
03793 
03794     // Log startup event.
03795     logType (LOG_BOOTED);
03796     logUint8 (gpsPosition.month);
03797     logUint8 (gpsPosition.day);
03798     logUint8 (gpsPosition.year & 0xff);
03799 
03800     logUint8 (gpsPosition.hours);
03801     logUint8 (gpsPosition.minutes);
03802     logUint8 (gpsPosition.seconds);
03803 
03804     // Counter and time to send packets if the GPS engine not available.
03805     lockLostCounter = 0;
03806     utcSeconds = gpsPosition.seconds;
03807     utcMinutes = gpsPosition.minutes;
03808 
03809     // Transmit software version packet on start up.
03810     tncTxPacket(TNC_BOOT_MESSAGE);
03811 
03812     // This is the main loop where we wait for timer ticks.
03813     for (;;) 
03814     {
03815         // Read the GPS engine serial port FIFO and process the GPS data.
03816         gpsUpdate();
03817 
03818         if (gpsIsReady()) 
03819         {
03820             // Start the flight timer when we get our first valid 3D fix and turn off the status LED.
03821             if (gpsGetFixType() == GPS_3D_FIX)
03822             {
03823                 timeSetRunFlag();
03824                 timeSetDutyCycle (TIME_DUTYCYCLE_0);
03825             } // END if
03826 
03827             // Transmit the packets in the desired time slots.
03828             switch (gpsPosition.seconds)
03829             {
03830                 case TNC_TIMESLOT:
03831                     switch (gpsPosition.minutes % 3)
03832                     {
03833                         case 0:
03834                             tncTxPacket(TNC_STATUS);
03835                              break;
03836 
03837                         case 1:
03838                             tncTxPacket(TNC_GGA);
03839                             break;
03840 
03841                         case 2:
03842                             tncTxPacket(TNC_RMC);
03843                             break;
03844                     } // END switch
03845 
03846                     break;
03847                 
03848                 case PSK31_TIMESLOT:
03849                     psk31TxPacket(gpsPosition.minutes);
03850                     break;
03851             } // END switch
03852 
03853             // Re-sync our internal clock to the UTC.
03854             utcSeconds = gpsPosition.seconds;
03855 
03856             lockLostCounter = 0;
03857 
03858             // Log the data to flash.
03859             if ((gpsPosition.seconds % 10) == 0)
03860                 sysLogGPSData();
03861 
03862             // Run the ballast pump as required.
03863             ballastCheck();
03864 
03865             cutDownCheck();
03866         } // END if
03867 
03868         // Processing that occurs once a second.
03869         if (timeUpdateFlag) 
03870         {
03871             // We maintain the UTC time in minutes and seconds in case the GPS engine stop operating.
03872             if (++utcSeconds == 60) 
03873             {
03874                 utcSeconds = 0;
03875                 
03876                 if (++utcMinutes == 60)
03877                     utcMinutes = 0;
03878             } // END if
03879 
03880             // If we loose the GPS for more than 5 seconds, we will determine when to send a packet based on internal time.
03881             if (lockLostCounter == 5) 
03882             {
03883                 // Transmit the packets in the desired time slots.
03884                 switch (utcSeconds)
03885                 {
03886                     case TNC_TIMESLOT:
03887                         switch (gpsPosition.minutes % 3)
03888                         {
03889                             case 0:
03890                                 tncTxPacket(TNC_STATUS);
03891                                  break;
03892     
03893                             case 1:
03894                                 tncTxPacket(TNC_GGA);
03895                                 break;
03896     
03897                             case 2:
03898                                 tncTxPacket(TNC_RMC);
03899                                 break;
03900                         } // END switch
03901 
03902                         break;
03903                     
03904                     case PSK31_TIMESLOT:
03905                         psk31TxPacket(utcMinutes);
03906                         break;
03907                 } // END switch
03908             } else
03909                 ++lockLostCounter;
03910 
03911             // Set the flag to indicate we have processed this time period.
03912             timeUpdateFlag = false;
03913         } // END if
03914 
03915         if (psk31IsMessageDone())
03916         {
03917             // Record the temperature post-transmit.
03918             logType (LOG_TEMPERATURE_2);
03919             logInt16 (lm92GetTemp());
03920         } // END if
03921 
03922     } // END while
03923 }

Generated on Mon Nov 12 10:03:00 2007 for HF-APRS Beacon by  doxygen 1.5.4