├── trackuino ├── radio.cpp ├── aprs.h ├── power.h ├── buzzer.h ├── pin.h ├── radio.h ├── radio_hx1.h ├── power_pic32.cpp ├── sensors_avr.h ├── sensors_pic32.h ├── ax25.h ├── gps.h ├── radio_hx1.cpp ├── pin_avr.cpp ├── pin_pic32.cpp ├── afsk_pic32.h ├── afsk_avr.h ├── power_avr.cpp ├── sensors_pic32.cpp ├── buzzer_pic32.cpp ├── aprs.cpp ├── buzzer_avr.cpp ├── sensors_avr.cpp ├── trackuino.ino ├── afsk_pic32.cpp ├── ax25.cpp ├── afsk_avr.cpp ├── afsk.cpp ├── config.h └── gps.cpp ├── WHATSNEW.md ├── README.md └── LICENSE /trackuino/radio.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | 19 | #include "radio.h" 20 | -------------------------------------------------------------------------------- /trackuino/aprs.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifndef __APRS_H__ 19 | #define __APRS_H__ 20 | 21 | void aprs_send(); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /trackuino/power.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | #ifndef __POWER_H__ 18 | #define __POWER_H__ 19 | 20 | void power_save(); 21 | 22 | #endif // ifndef __POWER_H__ 23 | 24 | -------------------------------------------------------------------------------- /trackuino/buzzer.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifndef __BUZZER_H__ 19 | #define __BUZZER_H__ 20 | 21 | void buzzer_setup(); 22 | void buzzer_on(); 23 | void buzzer_off(); 24 | 25 | #endif // ifndef __BUZZER_H__ 26 | -------------------------------------------------------------------------------- /trackuino/pin.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifndef __PIN_H__ 19 | #define __PIN_H__ 20 | 21 | #include 22 | 23 | void pin_write(uint8_t pin, uint8_t val); 24 | 25 | #endif // ifndef __PIN_H__ 26 | 27 | -------------------------------------------------------------------------------- /trackuino/radio.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifndef __RADIO_H__ 19 | #define __RADIO_H__ 20 | 21 | class Radio { 22 | public: 23 | virtual void setup() = 0; 24 | virtual void ptt_on() = 0; 25 | virtual void ptt_off() = 0; 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /trackuino/radio_hx1.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifndef __RADIO_HX1_H__ 19 | #define __RADIO_HX1_H__ 20 | 21 | #include "radio.h" 22 | 23 | class RadioHx1 : public Radio { 24 | public: 25 | virtual void setup(); 26 | virtual void ptt_on(); 27 | virtual void ptt_off(); 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /trackuino/power_pic32.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | #ifdef PIC32MX 18 | 19 | #include 20 | #include 21 | #include "config.h" 22 | #include "pin.h" 23 | 24 | void power_save() 25 | { 26 | pin_write(LED_PIN, LOW); 27 | PowerSaveIdle(); 28 | pin_write(LED_PIN, HIGH); 29 | } 30 | 31 | #endif // #ifdef PIC32MX 32 | -------------------------------------------------------------------------------- /trackuino/sensors_avr.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifdef AVR 19 | #ifndef __SENSORS_AVR_H__ 20 | #define __SENSORS_AVR_H__ 21 | 22 | void sensors_setup(); 23 | unsigned long sensors_aref(); 24 | long sensors_internal_temp(); 25 | int sensors_int_lm60(); 26 | int sensors_ext_lm60(); 27 | int sensors_vin(); 28 | 29 | #endif // ifndef __SENSORS_AVR_H__ 30 | #endif // ifdef AVR 31 | -------------------------------------------------------------------------------- /trackuino/sensors_pic32.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifdef PIC32MX 19 | #ifndef __SENSORS_PIC32_H__ 20 | #define __SENSORS_PIC32_H__ 21 | 22 | void sensors_setup(); 23 | unsigned long sensors_aref(); 24 | long sensors_internal_temp(); 25 | int sensors_int_lm60(); 26 | int sensors_ext_lm60(); 27 | int sensors_vin(); 28 | 29 | #endif // ifndef __SENSORS_PIC32_H__ 30 | #endif // ifdef PIC32MX 31 | -------------------------------------------------------------------------------- /trackuino/ax25.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifndef __AX25_H__ 19 | #define __AX25_H__ 20 | 21 | struct s_address { 22 | char callsign[7]; 23 | unsigned char ssid; 24 | }; 25 | 26 | void ax25_send_header(const struct s_address *addresses, int num_addresses); 27 | void ax25_send_byte(unsigned char byte); 28 | void ax25_send_string(const char *string); 29 | void ax25_send_footer(); 30 | void ax25_flush_frame(); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /trackuino/gps.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifndef __GPS_H__ 19 | #define __GPS_H__ 20 | 21 | #include 22 | 23 | extern char gps_time[7]; // HHMMSS 24 | extern uint32_t gps_seconds; // seconds after midnight 25 | extern char gps_date[7]; // DDMMYY 26 | extern float gps_lat; 27 | extern float gps_lon; 28 | extern char gps_aprs_lat[9]; 29 | extern char gps_aprs_lon[10]; 30 | extern float gps_course; 31 | extern float gps_speed; 32 | extern float gps_altitude; 33 | 34 | void gps_setup(); 35 | bool gps_decode(char c); 36 | void gps_reset_parser(); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /trackuino/radio_hx1.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #include "config.h" 19 | #include "pin.h" 20 | #include "radio_hx1.h" 21 | #if (ARDUINO + 1) >= 100 22 | # include 23 | #else 24 | # include 25 | #endif 26 | 27 | 28 | void RadioHx1::setup() 29 | { 30 | // Configure pins 31 | pinMode(PTT_PIN, OUTPUT); 32 | pin_write(PTT_PIN, LOW); 33 | pinMode(AUDIO_PIN, OUTPUT); 34 | } 35 | 36 | void RadioHx1::ptt_on() 37 | { 38 | pin_write(PTT_PIN, HIGH); 39 | delay(25); // The HX1 takes 5 ms from PTT to full RF, give it 25 40 | } 41 | 42 | void RadioHx1::ptt_off() 43 | { 44 | pin_write(PTT_PIN, LOW); 45 | } 46 | -------------------------------------------------------------------------------- /trackuino/pin_avr.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifdef AVR 19 | 20 | #include "pin.h" 21 | #include 22 | #include 23 | #if (ARDUINO + 1) >= 100 24 | # include 25 | #else 26 | # include 27 | #endif 28 | 29 | // This is a digitalWrite() replacement that does not disrupt 30 | // timer 2. 31 | void pin_write(uint8_t pin, uint8_t val) 32 | { 33 | uint8_t bit = digitalPinToBitMask(pin); 34 | uint8_t port = digitalPinToPort(pin); 35 | volatile uint8_t *out; 36 | 37 | if (port == NOT_A_PIN) return; 38 | 39 | out = portOutputRegister(port); 40 | 41 | if (val == LOW) { 42 | uint8_t oldSREG = SREG; 43 | cli(); 44 | *out &= ~bit; 45 | SREG = oldSREG; 46 | } else { 47 | uint8_t oldSREG = SREG; 48 | cli(); 49 | *out |= bit; 50 | SREG = oldSREG; 51 | } 52 | } 53 | 54 | #endif // AVR 55 | -------------------------------------------------------------------------------- /trackuino/pin_pic32.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | #ifdef PIC32MX 18 | 19 | #include "pin.h" 20 | #include 21 | #include 22 | #include 23 | 24 | // This is a digitalWrite() replacement that does not disrupt 25 | // timer 2. 26 | void pin_write(uint8_t pin, uint8_t val) 27 | { 28 | volatile p32_ioport * iop; 29 | uint8_t port; 30 | uint16_t bit; 31 | //* Get the port number for this pin. 32 | if ((pin >= NUM_DIGITAL_PINS) || ((port = digitalPinToPort(pin)) == NOT_A_PIN)) 33 | { 34 | return; 35 | } 36 | 37 | //* Obtain pointer to the registers for this io port. 38 | iop = (p32_ioport *)portRegisters(port); 39 | 40 | //* Obtain bit mask for the specific bit for this pin. 41 | bit = digitalPinToBitMask(pin); 42 | 43 | //* Set the pin state 44 | if (val == LOW) 45 | { 46 | iop->lat.clr = bit; 47 | } 48 | else 49 | { 50 | iop->lat.set = bit; 51 | } 52 | } 53 | 54 | 55 | #endif // PIC32MX 56 | 57 | -------------------------------------------------------------------------------- /trackuino/afsk_pic32.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifdef PIC32MX 19 | 20 | #ifndef __AFSK_PIC32_H__ 21 | #define __AFSK_PIC32_H__ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "config.h" 27 | 28 | #define AFSK_ISR extern "C" void __ISR(_TIMER_2_VECTOR, ipl6) T2_IntHandler (void) 29 | 30 | // Exported consts 31 | extern const uint32_t MODEM_CLOCK_RATE; 32 | extern const uint8_t REST_DUTY; 33 | extern const uint16_t TABLE_SIZE; 34 | extern const uint32_t PLAYBACK_RATE; 35 | 36 | // Exported vars 37 | extern const uint8_t afsk_sine_table[]; 38 | 39 | // Inline functions (this saves precious cycles in the ISR) 40 | inline uint8_t afsk_read_sample(int phase) 41 | { 42 | return afsk_sine_table[phase]; 43 | } 44 | 45 | inline void afsk_output_sample(uint8_t s) 46 | { 47 | SetDCOC1PWM(s); 48 | } 49 | 50 | inline void afsk_clear_interrupt_flag() 51 | { 52 | mT2ClearIntFlag(); 53 | } 54 | 55 | #ifdef DEBUG_MODEM 56 | inline uint16_t afsk_timer_counter() 57 | { 58 | return (uint16_t) TMR2; 59 | } 60 | 61 | inline int afsk_isr_overrun() 62 | { 63 | return (IFS0bits.T2IF); 64 | } 65 | #endif 66 | 67 | 68 | // Exported functions 69 | void afsk_setup(); 70 | void afsk_send(const uint8_t *buffer, int len); 71 | void afsk_start(); 72 | bool afsk_flush(); 73 | void afsk_isr(); 74 | void afsk_timer_setup(); 75 | void afsk_timer_start(); 76 | void afsk_timer_stop(); 77 | #ifdef DEBUG_MODEM 78 | void afsk_debug(); 79 | #endif 80 | 81 | #endif 82 | #endif // PIC32MX 83 | -------------------------------------------------------------------------------- /WHATSNEW.md: -------------------------------------------------------------------------------- 1 | Version 1.52 - 2016/08/25 2 | ------------------------- 3 | 4 | * FIX: Support U-BLOX M8 (and other Glonass / mixed GPSs), thanks to tmyrtle 5 | 6 | * FIX: GPS minor fixes / debug code cleanup, thanks to tmyrtle 7 | 8 | 9 | Version 1.51 - 2014/07/25 10 | ------------------------- 11 | 12 | * FIX: Compilation in Arduino 1.5.7 (deprecation of prog_uchar) 13 | 14 | * FIX: Renamed .pde -> .ino 15 | 16 | 17 | Version 1.5 - 2014/04/06 18 | ------------------------ 19 | 20 | * FIX: Allow compilation on Arduino 1.0+ 21 | 22 | * FIX: Added pre-emphasis flag, makes the signal more intelligible 23 | 24 | * FIX: Revamped modem code to avoid ISR overruns 25 | 26 | * FIX: improve baudrate accuracy 27 | 28 | 29 | Version 1.4 - 2012/08/26 30 | ------------------------ 31 | 32 | * NEW: Support for PIC32 / Chipkit Uno32 platform 33 | 34 | * NEW: Support for active or passive buzzers (DC or PWM driven) 35 | 36 | * NEW: Battery voltage sensing 37 | 38 | * NEW: Slotted transmissions for multilaunch events 39 | 40 | * REMOVED: Support for the MX146 radio 41 | 42 | 43 | Version 1.31 - 2011/08/02 44 | ------------------------- 45 | 46 | * FIX: Altitude 16-bit rollover 47 | 48 | 49 | Version 1.3 - 2011/07/05 50 | ------------------------ 51 | 52 | * FIX: More robust GPS parsing. It should improve compatibility with most 53 | NMEA-standard units. 54 | 55 | * FIX: Several optimizations in the modem module aimed at improving signal 56 | quality and reducing the chance of packet loss. 57 | 58 | * FIX: Cut down SRAM usage by 30% by moving the big sine table to PROGMEM. 59 | 60 | * NEW: Buzzer support for acoustic payload location. 61 | 62 | * NEW: Debug information to aid in testing the firmware without a radio. 63 | 64 | * NEW: The LED now indicates CPU activity. 65 | 66 | 67 | Version 1.2 - 2011/06/09 68 | ------------------------ 69 | 70 | * FIX: APRS messages reported 1/10th of the actual speed 71 | 72 | * NEW: Switch in config.h between celsius/farenheit/kelvin temperatures 73 | 74 | 75 | Version 1.1 - 2011/01/12 76 | ------------------------ 77 | 78 | * FIX: Eagle files: use soldermask under MOSFET Q5 as heat sink 79 | 80 | * FIX: TX LED's pin wasn't properly set as an output 81 | 82 | * FIX: Move code into the sketch's directory to avoid library clutter 83 | 84 | * NEW: Read internal/external temperatures from LM60 sensors 85 | 86 | 87 | Version 20100706 88 | ---------------- 89 | 90 | * First public release 91 | -------------------------------------------------------------------------------- /trackuino/afsk_avr.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifdef AVR 19 | 20 | #ifndef __AFSK_AVR_H__ 21 | #define __AFSK_AVR_H__ 22 | 23 | #include 24 | #include 25 | #include "config.h" 26 | 27 | #define AFSK_ISR ISR(TIMER2_OVF_vect) 28 | 29 | // Exported consts 30 | extern const uint32_t MODEM_CLOCK_RATE; 31 | extern const uint8_t REST_DUTY; 32 | extern const uint16_t TABLE_SIZE; 33 | extern const uint32_t PLAYBACK_RATE; 34 | 35 | // Exported vars 36 | extern const uint8_t afsk_sine_table[] PROGMEM; 37 | 38 | // Inline functions (this saves precious cycles in the ISR) 39 | #if AUDIO_PIN == 3 40 | # define OCR2 OCR2B 41 | #endif 42 | #if AUDIO_PIN == 11 43 | # define OCR2 OCR2A 44 | #endif 45 | 46 | inline uint8_t afsk_read_sample(int phase) 47 | { 48 | return pgm_read_byte_near(afsk_sine_table + phase); 49 | } 50 | 51 | inline void afsk_output_sample(uint8_t s) 52 | { 53 | OCR2 = s; 54 | } 55 | 56 | inline void afsk_clear_interrupt_flag() 57 | { 58 | // atmegas don't need this as opposed to pic32s. 59 | } 60 | 61 | #ifdef DEBUG_MODEM 62 | inline uint16_t afsk_timer_counter() 63 | { 64 | uint16_t t = TCNT2; 65 | if ((TIFR2 & _BV(TOV2)) && t < 128) 66 | t += 256; 67 | return t; 68 | } 69 | 70 | inline int afsk_isr_overrun() 71 | { 72 | return (TIFR2 & _BV(TOV2)); 73 | } 74 | #endif 75 | 76 | 77 | // Exported functions 78 | void afsk_setup(); 79 | void afsk_send(const uint8_t *buffer, int len); 80 | void afsk_start(); 81 | bool afsk_flush(); 82 | void afsk_isr(); 83 | void afsk_timer_setup(); 84 | void afsk_timer_start(); 85 | void afsk_timer_stop(); 86 | #ifdef DEBUG_MODEM 87 | void afsk_debug(); 88 | #endif 89 | 90 | #endif 91 | #endif // AVR 92 | -------------------------------------------------------------------------------- /trackuino/power_avr.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | #ifdef AVR 18 | 19 | #include 20 | #include 21 | #include 22 | #if (ARDUINO + 1) >= 100 23 | # include 24 | #else 25 | # include 26 | #endif 27 | #include "config.h" 28 | #include "pin.h" 29 | #include "power.h" 30 | 31 | void disable_bod_and_sleep() 32 | { 33 | /* This will turn off brown-out detection while 34 | * sleeping. Unfortunately this won't work in IDLE mode. 35 | * Relevant info about BOD disabling: datasheet p.44 36 | * 37 | * Procedure to disable the BOD: 38 | * 39 | * 1. BODSE and BODS must be set to 1 40 | * 2. Turn BODSE to 0 41 | * 3. BODS will automatically turn 0 after 4 cycles 42 | * 43 | * The catch is that we *must* go to sleep between 2 44 | * and 3, ie. just before BODS turns 0. 45 | */ 46 | unsigned char mcucr; 47 | 48 | cli(); 49 | mcucr = MCUCR | (_BV(BODS) | _BV(BODSE)); 50 | MCUCR = mcucr; 51 | MCUCR = mcucr & (~_BV(BODSE)); 52 | sei(); 53 | sleep_mode(); // Go to sleep 54 | } 55 | 56 | void power_save() 57 | { 58 | /* Enter power saving mode. SLEEP_MODE_IDLE is the least saving 59 | * mode, but it's the only one that will keep the UART running. 60 | * In addition, we need timer0 to keep track of time, timer 1 61 | * to drive the buzzer and timer2 to keep pwm output at its rest 62 | * voltage. 63 | */ 64 | 65 | set_sleep_mode(SLEEP_MODE_IDLE); 66 | sleep_enable(); 67 | power_adc_disable(); 68 | power_spi_disable(); 69 | power_twi_disable(); 70 | 71 | pin_write(LED_PIN, LOW); 72 | sleep_mode(); // Go to sleep 73 | pin_write(LED_PIN, HIGH); 74 | 75 | sleep_disable(); // Resume after wake up 76 | power_all_enable(); 77 | } 78 | 79 | 80 | #endif // #ifdef AVR 81 | -------------------------------------------------------------------------------- /trackuino/sensors_pic32.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | /* Credit to: 19 | * 20 | * cathedrow for this idea on using the ADC as a volt meter: 21 | * http://code.google.com/p/tinkerit/wiki/SecretVoltmeter 22 | */ 23 | 24 | #ifdef PIC32MX 25 | 26 | #include "config.h" 27 | #include "pin.h" 28 | #include "sensors_pic32.h" 29 | #include 30 | 31 | void sensors_setup() 32 | { 33 | pinMode(EXTERNAL_LM60_VS_PIN, OUTPUT); 34 | pinMode(INTERNAL_LM60_VS_PIN, OUTPUT); 35 | analogReference(DEFAULT); // Ref=AVDD, AVSS 36 | } 37 | 38 | int sensors_lm60(int powerPin, int readPin) 39 | { 40 | uint16_t adc = 0; 41 | pin_write(powerPin, HIGH); // Turn the LM60 on 42 | delayMicroseconds(5); // Allow time to settle 43 | adc = analogRead(readPin); // Real read 44 | pin_write(powerPin, LOW); // Turn the LM60 off 45 | int mV = 3300L * adc / 1024L; // Millivolts 46 | 47 | switch(TEMP_UNIT) { 48 | case 1: // C 49 | // Vo(mV) = (6.25*T) + 424 -> T = (Vo - 424) * 100 / 625 50 | return (4L * (mV - 424) / 25) + CALIBRATION_VAL; 51 | case 2: // K 52 | // C + 273 = K 53 | return (4L * (mV - 424) / 25) + 273 + CALIBRATION_VAL; 54 | case 3: // F 55 | // (9/5)C + 32 = F 56 | return (36L * (mV - 424) / 125) + 32 + CALIBRATION_VAL; 57 | } 58 | } 59 | 60 | int sensors_ext_lm60() 61 | { 62 | return sensors_lm60(EXTERNAL_LM60_VS_PIN, EXTERNAL_LM60_VOUT_PIN); 63 | } 64 | 65 | int sensors_int_lm60() 66 | { 67 | return sensors_lm60(INTERNAL_LM60_VS_PIN, INTERNAL_LM60_VOUT_PIN); 68 | } 69 | 70 | int sensors_vin() 71 | { 72 | uint16_t adc = analogRead(VMETER_PIN); 73 | uint16_t mV = 3300L * adc / 1024; 74 | 75 | // Vin = mV * R2 / (R1 + R2) 76 | int vin = (uint32_t)mV * (VMETER_R1 + VMETER_R2) / VMETER_R2; 77 | return vin; 78 | } 79 | 80 | 81 | #endif // ifdef PIC32MX 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Banner](https://github.com/trackuino/trackuino/wiki/img/trackuino-banner-narrow.png) 2 | 3 | This is the firmware for Trackuino, an open-source APRS tracker based on the Arduino platform. It was designed primarily to track high altitude balloons, so it has other handy features like reading temperature sensors and a buzzer for acoustic location. 4 | 5 | Trackuino is intended for use by licensed radio amateurs. 6 | 7 | Features 8 | ======== 9 | 10 | * Arduino shield form factor (you can stack more shields on it) 11 | * GPS: Venus 638FLPx. Reports okay above 18 Km. 12 | * Radio: Radiometrix's HX1 (300 mW). 13 | * 1200 bauds AFSK using 8-bit PWM 14 | * Sends out standard APRS position messages (latitude, longitude, altitude, course, speed and time). 15 | * Internal/external temperature sensors (LM60) to read temperature in and outside the payload 16 | * Active/passive buzzer support to ease acoustic payload location. 17 | * 2 x SMA female plugs (1 x GPS in + 1 x radio out) 18 | * Open source (GPLv2 license), both software and hardware. In other words, do whatever you want with it: modify it, add it to your project, etc. as long as you opensource your modifications as well. 19 | 20 | Download 21 | ======== 22 | 23 | The latest version is 1.52. 24 | 25 | Use the `Download ZIP` button to get the source code. 26 | 27 | Building 28 | ======== 29 | 30 | If you are building for the Arduino platform you need Arduino IDE version 0023 or higher (tested with versions 0023, 1.0.x and 1.5.x). Get it from the [Arduino web site](http://arduino.cc/). 31 | 32 | If you are building for the Chipkit Uno32 you need the Mpide IDE. Tested with 0023-20130715. Get it from the [Chipkit site](http://chipkit.net/). 33 | 34 | Unzip the firmware in your sketches directory and load it up by double-clicking on trackuino.ino. 35 | 36 | The single most important configuration file is "config.h". The file is self-documented. Here is where you set up your callsign, among other things. 37 | 38 | Flashing 39 | ======== 40 | 41 | **Important**: When flashing the Arduino/Uno32, remove the Venus GPS or the entire Trackuino shield. After flashing the firmware, you can plug it back in. The GPS and the host computer share the same serial port on the AVR, so they will conflict when used together. 42 | 43 | Hardware 44 | ======== 45 | 46 | The [Trackuino shield](https://github.com/trackuino/shield) repository contains the Eagle schematic / pcb files of a shield you can build as-is (gerber files are included) or modify to suit your needs. Check its README for details. 47 | 48 | Related projects 49 | ================ 50 | 51 | Some other HAB-related projects I wrote: 52 | 53 | * https://github.com/trackuino/hab-tracker - balloon trajectory prediction tool for Android 54 | * https://github.com/trackuino/aprsdb - an efficient and queriable APRS database server (required by the Hab Tracker Android app) 55 | * https://github.com/trackuino/chdk-intervalometer - a LUA intervalometer for the old Canon A570IS camera (which might work on other CHDK cameras too) 56 | 57 | Support 58 | ======= 59 | 60 | Discuss firmware bugs or suggestions in the issue tracker, or ask for help at the [SparkFun Forums](https://forum.sparkfun.com/). 61 | -------------------------------------------------------------------------------- /trackuino/buzzer_pic32.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | #ifdef PIC32MX 18 | 19 | #include "config.h" 20 | #include "buzzer.h" 21 | #include "pin.h" 22 | #include 23 | #include 24 | #include 25 | 26 | // Module constants 27 | static const unsigned long PWM_PERIOD = F_CPU / 8 / BUZZER_FREQ; 28 | static const unsigned long ON_CYCLES = BUZZER_FREQ * BUZZER_ON_TIME; 29 | static const unsigned long OFF_CYCLES = BUZZER_FREQ * BUZZER_OFF_TIME; 30 | #if BUZZER_TYPE == 0 // active buzzer 31 | static const uint16_t DUTY_CYCLE = PWM_PERIOD; 32 | #endif 33 | #if BUZZER_TYPE == 1 // passive buzzer 34 | static const uint16_t DUTY_CYCLE = PWM_PERIOD / 2; 35 | #endif 36 | 37 | // Module variables 38 | static volatile bool is_buzzer_on; 39 | static volatile bool buzzing; 40 | static unsigned long alarm; 41 | 42 | // Exported functions 43 | void buzzer_setup() 44 | { 45 | pinMode(BUZZER_PIN, OUTPUT); 46 | pin_write(BUZZER_PIN, LOW); 47 | buzzing = false; 48 | is_buzzer_on = false; 49 | alarm = 1; 50 | 51 | // There are two timers capable of PWM, 2 and 3. We are using 2 for the modem, 52 | // so use 3 for the buzzer. 53 | OpenTimer3(T3_ON | T3_PS_1_8, PWM_PERIOD); 54 | ConfigIntTimer3(T3_INT_ON | T3_INT_PRIOR_5); 55 | } 56 | 57 | void buzzer_on() 58 | { 59 | is_buzzer_on = true; 60 | } 61 | 62 | void buzzer_off() 63 | { 64 | is_buzzer_on = false; 65 | } 66 | 67 | // Interrupt Service Routine for TIMER 3. This is used to switch between the 68 | // buzzing and quiet periods when ON_CYCLES or OFF_CYCLES are reached. 69 | extern "C" void __ISR (_TIMER_3_VECTOR, ipl5) T3_IntHandler (void) 70 | { 71 | interrupts(); // allow other interrupts (ie. modem) 72 | alarm--; 73 | if (alarm == 0) { 74 | buzzing = !buzzing; 75 | if (is_buzzer_on && buzzing) { 76 | switch(BUZZER_PIN) { 77 | case 9: 78 | OpenOC4(OC_ON | OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE, DUTY_CYCLE, 0); 79 | break; 80 | case 10: 81 | OpenOC5(OC_ON | OC_TIMER3_SRC | OC_PWM_FAULT_PIN_DISABLE, DUTY_CYCLE, 0); 82 | break; 83 | } 84 | alarm = ON_CYCLES; 85 | } else { 86 | switch(BUZZER_PIN) { 87 | case 9: CloseOC4(); break; 88 | case 10: CloseOC5(); break; 89 | } 90 | alarm = OFF_CYCLES; 91 | pin_write(BUZZER_PIN, LOW); 92 | } 93 | } 94 | // Clear interrupt flag 95 | // This will break other interrupts and millis() (read+clear+write race condition?) 96 | // IFS0bits.T3IF = 0; // DON'T!! 97 | // Instead: 98 | mT3ClearIntFlag(); 99 | } 100 | 101 | #endif // #ifdef PIC32MX 102 | -------------------------------------------------------------------------------- /trackuino/aprs.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #include "config.h" 19 | #include "ax25.h" 20 | #include "gps.h" 21 | #include "aprs.h" 22 | #include "sensors_avr.h" 23 | #include "sensors_pic32.h" 24 | #include 25 | #include 26 | #if (ARDUINO + 1) >= 100 27 | # include 28 | #else 29 | # include 30 | #endif 31 | 32 | // Module functions 33 | float meters_to_feet(float m) 34 | { 35 | // 10000 ft = 3048 m 36 | return m / 0.3048; 37 | } 38 | 39 | // Exported functions 40 | void aprs_send() 41 | { 42 | char temp[12]; // Temperature (int/ext) 43 | const struct s_address addresses[] = { 44 | {D_CALLSIGN, D_CALLSIGN_ID}, // Destination callsign 45 | {S_CALLSIGN, S_CALLSIGN_ID}, // Source callsign (-11 = balloon, -9 = car) 46 | #ifdef DIGI_PATH1 47 | {DIGI_PATH1, DIGI_PATH1_TTL}, // Digi1 (first digi in the chain) 48 | #endif 49 | #ifdef DIGI_PATH2 50 | {DIGI_PATH2, DIGI_PATH2_TTL}, // Digi2 (second digi in the chain) 51 | #endif 52 | }; 53 | 54 | ax25_send_header(addresses, sizeof(addresses)/sizeof(s_address)); 55 | ax25_send_byte('/'); // Report w/ timestamp, no APRS messaging. $ = NMEA raw data 56 | // ax25_send_string("021709z"); // 021709z = 2nd day of the month, 17:09 zulu (UTC/GMT) 57 | ax25_send_string(gps_time); // 170915 = 17h:09m:15s zulu (not allowed in Status Reports) 58 | ax25_send_byte('h'); 59 | ax25_send_string(gps_aprs_lat); // Lat: 38deg and 22.20 min (.20 are NOT seconds, but 1/100th of minutes) 60 | ax25_send_byte('/'); // Symbol table 61 | ax25_send_string(gps_aprs_lon); // Lon: 000deg and 25.80 min 62 | ax25_send_byte('O'); // Symbol: O=balloon, -=QTH 63 | snprintf(temp, 4, "%03d", (int)(gps_course + 0.5)); 64 | ax25_send_string(temp); // Course (degrees) 65 | ax25_send_byte('/'); // and 66 | snprintf(temp, 4, "%03d", (int)(gps_speed + 0.5)); 67 | ax25_send_string(temp); // speed (knots) 68 | ax25_send_string("/A="); // Altitude (feet). Goes anywhere in the comment area 69 | snprintf(temp, 7, "%06ld", (long)(meters_to_feet(gps_altitude) + 0.5)); 70 | ax25_send_string(temp); 71 | ax25_send_string("/Ti="); 72 | snprintf(temp, 6, "%d", sensors_int_lm60()); 73 | ax25_send_string(temp); 74 | ax25_send_string("/Te="); 75 | snprintf(temp, 6, "%d", sensors_ext_lm60()); 76 | ax25_send_string(temp); 77 | ax25_send_string("/V="); 78 | snprintf(temp, 6, "%d", sensors_vin()); 79 | ax25_send_string(temp); 80 | ax25_send_byte(' '); 81 | ax25_send_string(APRS_COMMENT); // Comment 82 | ax25_send_footer(); 83 | 84 | ax25_flush_frame(); // Tell the modem to go 85 | } 86 | -------------------------------------------------------------------------------- /trackuino/buzzer_avr.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | #ifdef AVR 18 | 19 | #include "config.h" 20 | #include "buzzer.h" 21 | #include "pin.h" 22 | #if (ARDUINO + 1) >= 100 23 | # include 24 | #else 25 | # include 26 | #endif 27 | #include 28 | #include 29 | #include 30 | 31 | 32 | // Module constants 33 | static const unsigned long PWM_PERIOD = F_CPU / BUZZER_FREQ; 34 | static const unsigned long ON_CYCLES = BUZZER_FREQ * BUZZER_ON_TIME; 35 | static const unsigned long OFF_CYCLES = BUZZER_FREQ * BUZZER_OFF_TIME; 36 | #if BUZZER_TYPE == 0 // active buzzer 37 | static const uint16_t DUTY_CYCLE = PWM_PERIOD; 38 | #endif 39 | #if BUZZER_TYPE == 1 // passive buzzer 40 | static const uint16_t DUTY_CYCLE = PWM_PERIOD / 2; 41 | #endif 42 | 43 | // Module variables 44 | static volatile bool is_buzzer_on; 45 | static volatile bool buzzing; 46 | static volatile unsigned long alarm; 47 | 48 | // Exported functions 49 | void buzzer_setup() 50 | { 51 | pinMode(BUZZER_PIN, OUTPUT); 52 | pin_write(BUZZER_PIN, LOW); 53 | buzzing = false; 54 | is_buzzer_on = false; 55 | alarm = 1; 56 | 57 | // Top is ICR1 (WGM1=14), p.135 58 | TCCR1A = _BV(WGM11); 59 | TCCR1B = _BV(WGM13) | _BV(WGM12); 60 | 61 | // Set top to PWM_PERIOD 62 | ICR1 = PWM_PERIOD; 63 | 64 | // Enable interrupts on timer overflow 65 | TIMSK1 |= _BV(TOIE1); 66 | 67 | // Start the timer, no prescaler (CS1=1) 68 | TCCR1B |= _BV(CS10); 69 | } 70 | 71 | void buzzer_on() 72 | { 73 | is_buzzer_on = true; 74 | } 75 | 76 | void buzzer_off() 77 | { 78 | is_buzzer_on = false; 79 | } 80 | 81 | // Interrupt Service Routine for TIMER1. This is used to switch between the 82 | // buzzing and quiet periods when ON_CYCLES or OFF_CYCLES are reached. 83 | ISR (TIMER1_OVF_vect) 84 | { 85 | interrupts(); // allow other interrupts (ie. modem) 86 | alarm--; 87 | if (alarm == 0) { 88 | buzzing = !buzzing; 89 | if (is_buzzer_on && buzzing) { 90 | switch(BUZZER_PIN) { 91 | case 9: 92 | // Non-inverting pin 9 (COM1A=2), p.135 93 | TCCR1A |= _BV(COM1A1); 94 | OCR1A = DUTY_CYCLE; 95 | break; 96 | case 10: 97 | // Non-inverting pin 10 (COM1B=2), p.135 98 | TCCR1A |= _BV(COM1B1); 99 | OCR1B = DUTY_CYCLE; 100 | break; 101 | } 102 | alarm = ON_CYCLES; 103 | } else { 104 | switch(BUZZER_PIN) { 105 | // Disable PWM on pin 9/10 106 | case 9: TCCR1A &= ~_BV(COM1A1); break; 107 | case 10: TCCR1A &= ~_BV(COM1B1); break; 108 | } 109 | pin_write(BUZZER_PIN, LOW); 110 | alarm = OFF_CYCLES; 111 | } 112 | } 113 | } 114 | 115 | #endif // #ifdef AVR 116 | -------------------------------------------------------------------------------- /trackuino/sensors_avr.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | /* Credit to: 19 | * 20 | * cathedrow for this idea on using the ADC as a volt meter: 21 | * http://code.google.com/p/tinkerit/wiki/SecretVoltmeter 22 | */ 23 | 24 | #ifdef AVR 25 | 26 | #include "config.h" 27 | #include "pin.h" 28 | #include "sensors_avr.h" 29 | #if (ARDUINO + 1) >= 100 30 | # include 31 | #else 32 | # include 33 | #endif 34 | 35 | /* 36 | * sensors_aref: measure an external voltage hooked up to the AREF pin, 37 | * optionally (and recommendably) through a pull-up resistor. This is 38 | * incompatible with all other functions that use internal references 39 | * (see config.h) 40 | */ 41 | #ifdef USE_AREF 42 | void sensors_setup() 43 | { 44 | // Nothing to set-up when AREF is in use 45 | } 46 | 47 | unsigned long sensors_aref() 48 | { 49 | unsigned long result; 50 | // Read 1.1V reference against AREF (p. 262) 51 | ADMUX = _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 52 | delay(2); // Wait for Vref to settle 53 | ADCSRA |= _BV(ADSC); // Convert 54 | while (bit_is_set(ADCSRA,ADSC)); 55 | result = (ADCH << 8) | ADCL; 56 | 57 | // millivolts = 1.1 * 1024 * 1000 / result 58 | result = 1126400 / result; 59 | 60 | // aref = read aref * (32K + AREF_PULLUP) / 32K 61 | result = result * (32000UL + AREF_PULLUP) / 32000; 62 | 63 | return result; 64 | } 65 | #endif 66 | 67 | #ifndef USE_AREF 68 | void sensors_setup() 69 | { 70 | pinMode(INTERNAL_LM60_VS_PIN, OUTPUT); 71 | pinMode(EXTERNAL_LM60_VS_PIN, OUTPUT); 72 | } 73 | 74 | long sensors_internal_temp() 75 | { 76 | long result; 77 | // Read temperature sensor against 1.1V reference 78 | ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3); 79 | delay(2); // Wait for Vref to settle 80 | ADCSRA |= _BV(ADSC); // Convert 81 | while (bit_is_set(ADCSRA,ADSC)); 82 | result = (ADCH << 8) | ADCL; 83 | 84 | result = (result - 125) * 1075; 85 | 86 | return result; 87 | } 88 | 89 | int sensors_lm60(int powerPin, int readPin) 90 | { 91 | pin_write(powerPin, HIGH); // Turn the LM60 on 92 | analogReference(INTERNAL); // Ref=1.1V. Okay up to 108 degC (424 + 6.25*108 = 1100mV) 93 | analogRead(readPin); // Disregard the 1st conversion after changing ref (p.256) 94 | delay(10); // This is needed when switching references 95 | int adc = analogRead(readPin); // Real read 96 | pin_write(powerPin, LOW); // Turn the LM60 off 97 | 98 | int mV = 1100L * adc / 1024L; // Millivolts 99 | 100 | switch(TEMP_UNIT) { 101 | case 1: // C 102 | // Vo(mV) = (6.25*T) + 424 -> T = (Vo - 424) * 100 / 625 103 | return (4L * (mV - 424) / 25) + CALIBRATION_VAL; 104 | case 2: // K 105 | // C + 273 = K 106 | return (4L * (mV - 424) / 25) + 273 + CALIBRATION_VAL; 107 | case 3: // F 108 | // (9/5)C + 32 = F 109 | return (36L * (mV - 424) / 125) + 32 + CALIBRATION_VAL; 110 | } 111 | } 112 | 113 | int sensors_ext_lm60() 114 | { 115 | return sensors_lm60(EXTERNAL_LM60_VS_PIN, EXTERNAL_LM60_VOUT_PIN); 116 | } 117 | 118 | int sensors_int_lm60() 119 | { 120 | return sensors_lm60(INTERNAL_LM60_VS_PIN, INTERNAL_LM60_VOUT_PIN); 121 | } 122 | 123 | int sensors_vin() 124 | { 125 | analogReference(DEFAULT); // Ref=5V 126 | analogRead(VMETER_PIN); // Disregard the 1st conversion after changing ref (p.256) 127 | delay(10); // This is needed when switching references 128 | 129 | uint16_t adc = analogRead(VMETER_PIN); 130 | uint16_t mV = 5000L * adc / 1024; 131 | 132 | // Vin = mV * R2 / (R1 + R2) 133 | int vin = (uint32_t)mV * (VMETER_R1 + VMETER_R2) / VMETER_R2; 134 | return vin; 135 | } 136 | 137 | 138 | #endif 139 | #endif // ifdef AVR 140 | -------------------------------------------------------------------------------- /trackuino/trackuino.ino: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | // Mpide 22 fails to compile Arduino code because it stupidly defines ARDUINO 19 | // as an empty macro (hence the +0 hack). UNO32 builds are fine. Just use the 20 | // real Arduino IDE for Arduino builds. Optionally complain to the Mpide 21 | // authors to fix the broken macro. 22 | #if (ARDUINO + 0) == 0 23 | #error "Oops! We need the real Arduino IDE (version 22 or 23) for Arduino builds." 24 | #error "See trackuino.pde for details on this" 25 | 26 | // Refuse to compile on arduino version 21 or lower. 22 includes an 27 | // optimization of the USART code that is critical for real-time operation 28 | // of the AVR code. 29 | #elif (ARDUINO + 0) < 22 30 | #error "Oops! We need Arduino 22 or 23" 31 | #error "See trackuino.pde for details on this" 32 | 33 | #endif 34 | 35 | 36 | // Trackuino custom libs 37 | #include "config.h" 38 | #include "afsk_avr.h" 39 | #include "afsk_pic32.h" 40 | #include "aprs.h" 41 | #include "buzzer.h" 42 | #include "gps.h" 43 | #include "pin.h" 44 | #include "power.h" 45 | #include "sensors_avr.h" 46 | #include "sensors_pic32.h" 47 | 48 | // Arduino/AVR libs 49 | #if (ARDUINO + 1) >= 100 50 | # include 51 | #else 52 | # include 53 | #endif 54 | 55 | // Module constants 56 | static const uint32_t VALID_POS_TIMEOUT = 2000; // ms 57 | 58 | // Module variables 59 | static int32_t next_aprs = 0; 60 | 61 | 62 | void setup() 63 | { 64 | pinMode(LED_PIN, OUTPUT); 65 | pin_write(LED_PIN, LOW); 66 | 67 | Serial.begin(GPS_BAUDRATE); 68 | #ifdef DEBUG_RESET 69 | Serial.println("RESET"); 70 | #endif 71 | 72 | buzzer_setup(); 73 | afsk_setup(); 74 | gps_setup(); 75 | sensors_setup(); 76 | 77 | #ifdef DEBUG_SENS 78 | Serial.print("Ti="); 79 | Serial.print(sensors_int_lm60()); 80 | Serial.print(", Te="); 81 | Serial.print(sensors_ext_lm60()); 82 | Serial.print(", Vin="); 83 | Serial.println(sensors_vin()); 84 | #endif 85 | 86 | // Do not start until we get a valid time reference 87 | // for slotted transmissions. 88 | if (APRS_SLOT >= 0) { 89 | do { 90 | while (! Serial.available()) 91 | power_save(); 92 | } while (! gps_decode(Serial.read())); 93 | 94 | next_aprs = millis() + 1000 * 95 | (APRS_PERIOD - (gps_seconds + APRS_PERIOD - APRS_SLOT) % APRS_PERIOD); 96 | } 97 | else { 98 | next_aprs = millis(); 99 | } 100 | // TODO: beep while we get a fix, maybe indicating the number of 101 | // visible satellites by a series of short beeps? 102 | } 103 | 104 | void get_pos() 105 | { 106 | // Get a valid position from the GPS 107 | int valid_pos = 0; 108 | uint32_t timeout = millis(); 109 | 110 | #ifdef DEBUG_GPS 111 | Serial.println("\nget_pos()"); 112 | #endif 113 | 114 | gps_reset_parser(); 115 | 116 | do { 117 | if (Serial.available()) 118 | valid_pos = gps_decode(Serial.read()); 119 | } while ( (millis() - timeout < VALID_POS_TIMEOUT) && ! valid_pos) ; 120 | 121 | if (valid_pos) { 122 | if (gps_altitude > BUZZER_ALTITUDE) { 123 | buzzer_off(); // In space, no one can hear you buzz 124 | } else { 125 | buzzer_on(); 126 | } 127 | } 128 | } 129 | 130 | void loop() 131 | { 132 | // Time for another APRS frame 133 | if ((int32_t) (millis() - next_aprs) >= 0) { 134 | get_pos(); 135 | aprs_send(); 136 | next_aprs += APRS_PERIOD * 1000L; 137 | while (afsk_flush()) { 138 | power_save(); 139 | } 140 | 141 | #ifdef DEBUG_MODEM 142 | // Show modem ISR stats from the previous transmission 143 | afsk_debug(); 144 | #endif 145 | 146 | } else { 147 | // Discard GPS data received during sleep window 148 | while (Serial.available()) { 149 | Serial.read(); 150 | } 151 | } 152 | 153 | power_save(); // Incoming GPS data or interrupts will wake us up 154 | } 155 | -------------------------------------------------------------------------------- /trackuino/afsk_pic32.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | #ifdef PIC32MX 18 | 19 | #include "config.h" 20 | #include "pin.h" 21 | #include 22 | #include 23 | #include 24 | 25 | #if AUDIO_PIN == 3 26 | # define OCxRS OC1RS 27 | # define OCxCON OC1CON 28 | #endif 29 | #if AUDIO_PIN == 11 30 | # error Oops! The Uno32 cannot do PWM on pin 11 31 | #endif 32 | 33 | // Module constants 34 | extern const uint8_t afsk_sine_table[512] = { 35 | 127, 129, 130, 132, 133, 135, 136, 138, 139, 141, 143, 144, 146, 147, 149, 150, 152, 153, 155, 156, 158, 36 | 159, 161, 163, 164, 166, 167, 168, 170, 171, 173, 174, 176, 177, 179, 180, 182, 183, 184, 186, 187, 188, 37 | 190, 191, 193, 194, 195, 197, 198, 199, 200, 202, 203, 204, 205, 207, 208, 209, 210, 211, 213, 214, 215, 38 | 216, 217, 218, 219, 220, 221, 223, 224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 39 | 236, 237, 238, 239, 239, 240, 241, 242, 242, 243, 244, 244, 245, 245, 246, 247, 247, 248, 248, 249, 249, 40 | 249, 250, 250, 251, 251, 251, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 41 | 254, 254, 255, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253, 253, 253, 253, 252, 252, 252, 251, 42 | 251, 251, 250, 250, 249, 249, 249, 248, 248, 247, 247, 246, 245, 245, 244, 244, 243, 242, 242, 241, 240, 43 | 239, 239, 238, 237, 236, 236, 235, 234, 233, 232, 231, 230, 229, 228, 228, 227, 226, 225, 224, 223, 221, 44 | 220, 219, 218, 217, 216, 215, 214, 213, 211, 210, 209, 208, 207, 205, 204, 203, 202, 200, 199, 198, 197, 45 | 195, 194, 193, 191, 190, 188, 187, 186, 184, 183, 182, 180, 179, 177, 176, 174, 173, 171, 170, 168, 167, 46 | 166, 164, 163, 161, 159, 158, 156, 155, 153, 152, 150, 149, 147, 146, 144, 143, 141, 139, 138, 136, 135, 47 | 133, 132, 130, 129, 127, 125, 124, 122, 121, 119, 118, 116, 115, 113, 111, 110, 108, 107, 105, 104, 102, 48 | 101, 99, 98, 96, 95, 93, 91, 90, 88, 87, 86, 84, 83, 81, 80, 78, 77, 75, 74, 72, 71, 49 | 70, 68, 67, 66, 64, 63, 61, 60, 59, 57, 56, 55, 54, 52, 51, 50, 49, 47, 46, 45, 44, 50 | 43, 41, 40, 39, 38, 37, 36, 35, 34, 33, 31, 30, 29, 28, 27, 26, 26, 25, 24, 23, 22, 51 | 21, 20, 19, 18, 18, 17, 16, 15, 15, 14, 13, 12, 12, 11, 10, 10, 9, 9, 8, 7, 7, 52 | 6, 6, 5, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 54 | 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 55 | 12, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 56 | 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 49, 50, 51, 52, 57 | 54, 55, 56, 57, 59, 60, 61, 63, 64, 66, 67, 68, 70, 71, 72, 74, 75, 77, 78, 80, 81, 58 | 83, 84, 86, 87, 88, 90, 91, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 111, 113, 59 | 115, 116, 118, 119, 121, 122, 124, 125 60 | }; 61 | 62 | // External constants 63 | extern const uint32_t MODEM_CLOCK_RATE = F_CPU / 2; // 40 MHz 64 | extern const uint8_t REST_DUTY = 127; 65 | extern const uint16_t TABLE_SIZE = sizeof(afsk_sine_table); 66 | extern const uint32_t PLAYBACK_RATE = MODEM_CLOCK_RATE / 256; 67 | 68 | 69 | // External functions 70 | void afsk_timer_setup() 71 | { 72 | OpenTimer2(T2_ON | T2_PS_1_2, 0xFF); 73 | OpenOC1(OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0); 74 | SetDCOC1PWM(REST_DUTY); 75 | 76 | // Use pin 43 on the Uno32 as PTT indicator 77 | pinMode(43, OUTPUT); 78 | 79 | } 80 | 81 | void afsk_timer_start() 82 | { 83 | // Prepare timer 2 84 | ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_6); 85 | 86 | // Turn PTT led on 87 | pin_write(43, HIGH); 88 | } 89 | 90 | void afsk_timer_stop() 91 | { 92 | // Return to rest duty cycle 93 | SetDCOC1PWM(REST_DUTY); 94 | 95 | // Disable playback interrupt 96 | mT2IntEnable(0); 97 | 98 | // Turn PTT led off 99 | pin_write(43, LOW); 100 | } 101 | 102 | 103 | #endif // ifdef PIC32MX 104 | -------------------------------------------------------------------------------- /trackuino/ax25.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #include "ax25.h" 19 | #include "config.h" 20 | #include "afsk_avr.h" 21 | #include "afsk_pic32.h" 22 | #include 23 | #if (ARDUINO + 1) >= 100 24 | # include 25 | #else 26 | # include 27 | #endif 28 | 29 | // Module constants 30 | static const unsigned int MAX_PACKET = 512; // bytes 31 | 32 | // Module globals 33 | static uint16_t crc; 34 | static uint8_t ones_in_a_row; 35 | static uint8_t packet[MAX_PACKET]; 36 | static unsigned int packet_size; 37 | 38 | // Module functions 39 | static void 40 | update_crc(uint8_t a_bit) 41 | { 42 | crc ^= a_bit; 43 | if (crc & 1) 44 | crc = (crc >> 1) ^ 0x8408; // X-modem CRC poly 45 | else 46 | crc = crc >> 1; 47 | } 48 | 49 | static void 50 | send_byte(uint8_t a_byte) 51 | { 52 | uint8_t i = 0; 53 | while (i++ < 8) { 54 | uint8_t a_bit = a_byte & 1; 55 | a_byte >>= 1; 56 | update_crc(a_bit); 57 | if (a_bit) { 58 | // Next bit is a '1' 59 | if (packet_size >= MAX_PACKET * 8) // Prevent buffer overrun 60 | return; 61 | packet[packet_size >> 3] |= (1 << (packet_size & 7)); 62 | packet_size++; 63 | if (++ones_in_a_row < 5) continue; 64 | } 65 | // Next bit is a '0' or a zero padding after 5 ones in a row 66 | if (packet_size >= MAX_PACKET * 8) // Prevent buffer overrun 67 | return; 68 | packet[packet_size >> 3] &= ~(1 << (packet_size & 7)); 69 | packet_size++; 70 | ones_in_a_row = 0; 71 | } 72 | } 73 | 74 | // Exported functions 75 | void 76 | ax25_send_byte(uint8_t a_byte) 77 | { 78 | // Wrap around send_byte, but prints debug info 79 | send_byte(a_byte); 80 | #ifdef DEBUG_AX25 81 | Serial.print((char)a_byte); 82 | #endif 83 | } 84 | 85 | void 86 | ax25_send_flag() 87 | { 88 | uint8_t flag = 0x7e; 89 | int i; 90 | for (i = 0; i < 8; i++, packet_size++) { 91 | if (packet_size >= MAX_PACKET * 8) // Prevent buffer overrun 92 | return; 93 | if ((flag >> i) & 1) 94 | packet[packet_size >> 3] |= (1 << (packet_size & 7)); 95 | else 96 | packet[packet_size >> 3] &= ~(1 << (packet_size & 7)); 97 | } 98 | } 99 | 100 | void 101 | ax25_send_string(const char *string) 102 | { 103 | int i; 104 | for (i = 0; string[i]; i++) { 105 | ax25_send_byte(string[i]); 106 | } 107 | } 108 | 109 | void 110 | ax25_send_header(const struct s_address *addresses, int num_addresses) 111 | { 112 | int i, j; 113 | packet_size = 0; 114 | ones_in_a_row = 0; 115 | crc = 0xffff; 116 | 117 | // Send flags during TX_DELAY milliseconds (8 bit-flag = 8000/1200 ms) 118 | for (i = 0; i < TX_DELAY * 3 / 20; i++) { 119 | ax25_send_flag(); 120 | } 121 | 122 | for (i = 0; i < num_addresses; i++) { 123 | // Transmit callsign 124 | for (j = 0; addresses[i].callsign[j]; j++) 125 | send_byte(addresses[i].callsign[j] << 1); 126 | // Transmit pad 127 | for ( ; j < 6; j++) 128 | send_byte(' ' << 1); 129 | // Transmit SSID. Termination signaled with last bit = 1 130 | if (i == num_addresses - 1) 131 | send_byte(('0' + addresses[i].ssid) << 1 | 1); 132 | else 133 | send_byte(('0' + addresses[i].ssid) << 1); 134 | } 135 | 136 | // Control field: 3 = APRS-UI frame 137 | send_byte(0x03); 138 | 139 | // Protocol ID: 0xf0 = no layer 3 data 140 | send_byte(0xf0); 141 | 142 | #ifdef DEBUG_AX25 143 | // Print source callsign 144 | Serial.println(); 145 | Serial.print('['); 146 | Serial.print(millis()); 147 | Serial.print("] "); 148 | Serial.print(addresses[1].callsign); 149 | if (addresses[1].ssid) { 150 | Serial.print('-'); 151 | Serial.print((unsigned int)addresses[1].ssid); 152 | } 153 | Serial.print('>'); 154 | // Destination callsign 155 | Serial.print(addresses[0].callsign); 156 | if (addresses[0].ssid) { 157 | Serial.print('-'); 158 | Serial.print((unsigned int)addresses[0].ssid); 159 | } 160 | for (i = 2; i < num_addresses; i++) { 161 | Serial.print(','); 162 | Serial.print(addresses[i].callsign); 163 | if (addresses[i].ssid) { 164 | Serial.print('-'); 165 | Serial.print((unsigned int)addresses[i].ssid); 166 | } 167 | } 168 | Serial.print(':'); 169 | #endif 170 | } 171 | 172 | void 173 | ax25_send_footer() 174 | { 175 | // Save the crc so that it can be treated it atomically 176 | uint16_t final_crc = crc; 177 | 178 | // Send the CRC 179 | send_byte(~(final_crc & 0xff)); 180 | final_crc >>= 8; 181 | send_byte(~(final_crc & 0xff)); 182 | 183 | // Signal the end of frame 184 | ax25_send_flag(); 185 | #ifdef DEBUG_AX25 186 | Serial.println(); 187 | #endif 188 | } 189 | 190 | void 191 | ax25_flush_frame() 192 | { 193 | // Key the transmitter and send the frame 194 | afsk_send(packet, packet_size); 195 | afsk_start(); 196 | } 197 | 198 | 199 | -------------------------------------------------------------------------------- /trackuino/afsk_avr.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | #ifdef AVR 18 | 19 | #include 20 | #include 21 | #include "config.h" 22 | #include "afsk_avr.h" 23 | 24 | 25 | // Module consts 26 | 27 | /* The sine_table is the carrier signal. To achieve phase continuity, each tone 28 | * starts at the index where the previous one left off. By changing the stride of 29 | * the index (phase_delta) we get 1200 or 2200 Hz. The PHASE_DELTA_XXXX values 30 | * can be calculated as: 31 | * 32 | * Fg = frequency of the output tone (1200 or 2200) 33 | * Fm = sampling rate (PLAYBACK_RATE_HZ) 34 | * Tt = sine table size (TABLE_SIZE) 35 | * 36 | * PHASE_DELTA_Fg = Tt*(Fg/Fm) 37 | */ 38 | 39 | // This procudes a "warning: only initialized variables can be placed into 40 | // program memory area", which can be safely ignored: 41 | // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734 42 | extern const uint8_t afsk_sine_table[512] PROGMEM = { 43 | 127, 129, 130, 132, 133, 135, 136, 138, 139, 141, 143, 144, 146, 147, 149, 150, 152, 153, 155, 156, 158, 44 | 159, 161, 163, 164, 166, 167, 168, 170, 171, 173, 174, 176, 177, 179, 180, 182, 183, 184, 186, 187, 188, 45 | 190, 191, 193, 194, 195, 197, 198, 199, 200, 202, 203, 204, 205, 207, 208, 209, 210, 211, 213, 214, 215, 46 | 216, 217, 218, 219, 220, 221, 223, 224, 225, 226, 227, 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 47 | 236, 237, 238, 239, 239, 240, 241, 242, 242, 243, 244, 244, 245, 245, 246, 247, 247, 248, 248, 249, 249, 48 | 249, 250, 250, 251, 251, 251, 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 49 | 254, 254, 255, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253, 253, 253, 253, 252, 252, 252, 251, 50 | 251, 251, 250, 250, 249, 249, 249, 248, 248, 247, 247, 246, 245, 245, 244, 244, 243, 242, 242, 241, 240, 51 | 239, 239, 238, 237, 236, 236, 235, 234, 233, 232, 231, 230, 229, 228, 228, 227, 226, 225, 224, 223, 221, 52 | 220, 219, 218, 217, 216, 215, 214, 213, 211, 210, 209, 208, 207, 205, 204, 203, 202, 200, 199, 198, 197, 53 | 195, 194, 193, 191, 190, 188, 187, 186, 184, 183, 182, 180, 179, 177, 176, 174, 173, 171, 170, 168, 167, 54 | 166, 164, 163, 161, 159, 158, 156, 155, 153, 152, 150, 149, 147, 146, 144, 143, 141, 139, 138, 136, 135, 55 | 133, 132, 130, 129, 127, 125, 124, 122, 121, 119, 118, 116, 115, 113, 111, 110, 108, 107, 105, 104, 102, 56 | 101, 99, 98, 96, 95, 93, 91, 90, 88, 87, 86, 84, 83, 81, 80, 78, 77, 75, 74, 72, 71, 57 | 70, 68, 67, 66, 64, 63, 61, 60, 59, 57, 56, 55, 54, 52, 51, 50, 49, 47, 46, 45, 44, 58 | 43, 41, 40, 39, 38, 37, 36, 35, 34, 33, 31, 30, 29, 28, 27, 26, 26, 25, 24, 23, 22, 59 | 21, 20, 19, 18, 18, 17, 16, 15, 15, 14, 13, 12, 12, 11, 10, 10, 9, 9, 8, 7, 7, 60 | 6, 6, 5, 5, 5, 4, 4, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 61 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 62 | 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 63 | 12, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 28, 64 | 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 49, 50, 51, 52, 65 | 54, 55, 56, 57, 59, 60, 61, 63, 64, 66, 67, 68, 70, 71, 72, 74, 75, 77, 78, 80, 81, 66 | 83, 84, 86, 87, 88, 90, 91, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 108, 110, 111, 113, 67 | 115, 116, 118, 119, 121, 122, 124, 125 68 | }; 69 | 70 | // External consts 71 | 72 | extern const uint32_t MODEM_CLOCK_RATE = F_CPU; // 16 MHz 73 | extern const uint8_t REST_DUTY = 127; 74 | extern const uint16_t TABLE_SIZE = sizeof(afsk_sine_table); 75 | //extern const uint32_t PLAYBACK_RATE = MODEM_CLOCK_RATE / 510; // Phase correct PWM 76 | extern const uint32_t PLAYBACK_RATE = MODEM_CLOCK_RATE / 256; // Fast PWM 77 | 78 | 79 | // Exported functions 80 | 81 | void afsk_timer_setup() 82 | { 83 | // Set up Timer 2 to do pulse width modulation on the speaker 84 | // pin. 85 | 86 | // Source timer2 from clkIO (datasheet p.164) 87 | ASSR &= ~(_BV(EXCLK) | _BV(AS2)); 88 | 89 | // Set fast PWM mode with TOP = 0xff: WGM22:0 = 3 (p.150) 90 | // This allows 256 cycles per sample and gives 16M/256 = 62.5 KHz PWM rate 91 | 92 | TCCR2A |= _BV(WGM21) | _BV(WGM20); 93 | TCCR2B &= ~_BV(WGM22); 94 | 95 | // Phase correct PWM with top = 0xff: WGM22:0 = 1 (p.152 and p.160)) 96 | // This allows 510 cycles per sample and gives 16M/510 = ~31.4 KHz PWM rate 97 | //TCCR2A = (TCCR2A | _BV(WGM20)) & ~_BV(WGM21); 98 | //TCCR2B &= ~_BV(WGM22); 99 | 100 | #if AUDIO_PIN == 11 101 | // Do non-inverting PWM on pin OC2A (arduino pin 11) (p.159) 102 | // OC2B (arduino pin 3) stays in normal port operation: 103 | // COM2A1=1, COM2A0=0, COM2B1=0, COM2B0=0 104 | TCCR2A = (TCCR2A | _BV(COM2A1)) & ~(_BV(COM2A0) | _BV(COM2B1) | _BV(COM2B0)); 105 | #endif 106 | 107 | #if AUDIO_PIN == 3 108 | // Do non-inverting PWM on pin OC2B (arduino pin 3) (p.159). 109 | // OC2A (arduino pin 11) stays in normal port operation: 110 | // COM2B1=1, COM2B0=0, COM2A1=0, COM2A0=0 111 | TCCR2A = (TCCR2A | _BV(COM2B1)) & ~(_BV(COM2B0) | _BV(COM2A1) | _BV(COM2A0)); 112 | #endif 113 | 114 | // No prescaler (p.162) 115 | TCCR2B = (TCCR2B & ~(_BV(CS22) | _BV(CS21))) | _BV(CS20); 116 | // prescaler x8 for slow-mo testing 117 | //TCCR2B = (TCCR2B & ~(_BV(CS22) | _BV(CS20))) | _BV(CS21); 118 | 119 | // Set initial pulse width to the rest position (0v after DC decoupling) 120 | OCR2 = REST_DUTY; 121 | } 122 | 123 | void afsk_timer_start() 124 | { 125 | // Clear the overflow flag, so that the interrupt doesn't go off 126 | // immediately and overrun the next one (p.163). 127 | TIFR2 |= _BV(TOV2); // Yeah, writing a 1 clears the flag. 128 | 129 | // Enable interrupt when TCNT2 reaches TOP (0xFF) (p.151, 163) 130 | TIMSK2 |= _BV(TOIE2); 131 | } 132 | 133 | void afsk_timer_stop() 134 | { 135 | // Output 0v (after DC coupling) 136 | OCR2 = REST_DUTY; 137 | 138 | // Disable playback interrupt 139 | TIMSK2 &= ~_BV(TOIE2); 140 | } 141 | 142 | 143 | 144 | #endif // ifdef AVR 145 | -------------------------------------------------------------------------------- /trackuino/afsk.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | /* Credit to: 19 | * 20 | * Michael Smith for his Example of Audio generation with two timers and PWM: 21 | * http://www.arduino.cc/playground/Code/PCMAudio 22 | * 23 | * Ken Shirriff for his Great article on PWM: 24 | * http://arcfn.com/2009/07/secrets-of-arduino-pwm.html 25 | * 26 | * The large group of people who created the free AVR tools. 27 | * Documentation on interrupts: 28 | * http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html 29 | */ 30 | 31 | #include "config.h" 32 | #include "afsk_avr.h" 33 | #include "afsk_pic32.h" 34 | #include "pin.h" 35 | #include "radio_hx1.h" 36 | #if (ARDUINO + 1) >= 100 37 | # include 38 | #else 39 | # include 40 | #endif 41 | #include 42 | 43 | // Module consts 44 | 45 | // The actual baudrate after rounding errors will be: 46 | // PLAYBACK_RATE / (integer_part_of((PLAYBACK_RATE * 256) / BAUD_RATE) / 256) 47 | static const uint16_t BAUD_RATE = 1200; 48 | static const uint16_t SAMPLES_PER_BAUD = ((uint32_t)PLAYBACK_RATE << 8) / BAUD_RATE; // Fixed point 8.8 49 | static const uint16_t PHASE_DELTA_1200 = (((TABLE_SIZE * 1200UL) << 7) / PLAYBACK_RATE); // Fixed point 9.7 50 | static const uint16_t PHASE_DELTA_2200 = (((TABLE_SIZE * 2200UL) << 7) / PLAYBACK_RATE); 51 | static const uint8_t SAMPLE_FIFO_SIZE = 32; 52 | 53 | 54 | // Module globals 55 | volatile static uint8_t current_byte; 56 | volatile static uint16_t current_sample_in_baud; // 1 bit = SAMPLES_PER_BAUD samples 57 | volatile static bool go = false; // Modem is on 58 | volatile static uint16_t phase_delta; // 1200/2200 for standard AX.25 59 | volatile static uint16_t phase; // Fixed point 9.7 (2PI = TABLE_SIZE) 60 | volatile static uint16_t packet_pos; // Next bit to be sent out 61 | volatile static uint8_t sample_fifo[SAMPLE_FIFO_SIZE]; // queue of samples 62 | volatile static uint8_t sample_fifo_head = 0; // empty when head == tail 63 | volatile static uint8_t sample_fifo_tail = 0; 64 | volatile static uint32_t sample_overruns = 0; 65 | 66 | // The radio (class defined in config.h) 67 | static RadioHx1 radio; 68 | 69 | volatile static unsigned int afsk_packet_size = 0; 70 | volatile static const uint8_t *afsk_packet; 71 | 72 | 73 | // Module functions 74 | 75 | inline static bool afsk_is_fifo_full() 76 | { 77 | return (((sample_fifo_head + 1) % SAMPLE_FIFO_SIZE) == sample_fifo_tail); 78 | } 79 | 80 | inline static bool afsk_is_fifo_full_safe() 81 | { 82 | noInterrupts(); 83 | boolean b = afsk_is_fifo_full(); 84 | interrupts(); 85 | return b; 86 | } 87 | 88 | inline static bool afsk_is_fifo_empty() 89 | { 90 | return (sample_fifo_head == sample_fifo_tail); 91 | } 92 | 93 | inline static bool afsk_is_fifo_empty_safe() 94 | { 95 | noInterrupts(); 96 | bool b = afsk_is_fifo_empty(); 97 | interrupts(); 98 | return b; 99 | } 100 | 101 | inline static void afsk_fifo_in(uint8_t s) 102 | { 103 | sample_fifo[sample_fifo_head] = s; 104 | sample_fifo_head = (sample_fifo_head + 1) % SAMPLE_FIFO_SIZE; 105 | } 106 | 107 | inline static void afsk_fifo_in_safe(uint8_t s) 108 | { 109 | noInterrupts(); 110 | afsk_fifo_in(s); 111 | interrupts(); 112 | } 113 | 114 | inline static uint8_t afsk_fifo_out() 115 | { 116 | uint8_t s = sample_fifo[sample_fifo_tail]; 117 | sample_fifo_tail = (sample_fifo_tail + 1) % SAMPLE_FIFO_SIZE; 118 | return s; 119 | } 120 | 121 | inline static uint8_t afsk_fifo_out_safe() 122 | { 123 | noInterrupts(); 124 | uint8_t b = afsk_fifo_out(); 125 | interrupts(); 126 | return b; 127 | } 128 | 129 | 130 | // Exported functions 131 | 132 | void afsk_setup() 133 | { 134 | // Start radio 135 | radio.setup(); 136 | } 137 | 138 | void afsk_send(const uint8_t *buffer, int len) 139 | { 140 | afsk_packet_size = len; 141 | afsk_packet = buffer; 142 | } 143 | 144 | void afsk_start() 145 | { 146 | phase_delta = PHASE_DELTA_1200; 147 | phase = 0; 148 | packet_pos = 0; 149 | current_sample_in_baud = 0; 150 | go = true; 151 | 152 | // Prime the fifo 153 | afsk_flush(); 154 | 155 | // Start timer (CPU-specific) 156 | afsk_timer_setup(); 157 | 158 | // Key the radio 159 | radio.ptt_on(); 160 | 161 | // Start transmission 162 | afsk_timer_start(); 163 | } 164 | 165 | bool afsk_flush() 166 | { 167 | while (! afsk_is_fifo_full_safe()) { 168 | // If done sending packet 169 | if (packet_pos == afsk_packet_size) { 170 | go = false; // End of transmission 171 | } 172 | if (go == false) { 173 | if (afsk_is_fifo_empty_safe()) { 174 | afsk_timer_stop(); // Disable modem 175 | radio.ptt_off(); // Release PTT 176 | return false; // Done 177 | } else { 178 | return true; 179 | } 180 | } 181 | 182 | // If sent SAMPLES_PER_BAUD already, go to the next bit 183 | if (current_sample_in_baud < (1 << 8)) { // Load up next bit 184 | if ((packet_pos & 7) == 0) { // Load up next byte 185 | current_byte = afsk_packet[packet_pos >> 3]; 186 | } else { 187 | current_byte = current_byte / 2; // ">>1" forces int conversion 188 | } 189 | if ((current_byte & 1) == 0) { 190 | // Toggle tone (1200 <> 2200) 191 | phase_delta ^= (PHASE_DELTA_1200 ^ PHASE_DELTA_2200); 192 | } 193 | } 194 | 195 | phase += phase_delta; 196 | uint8_t s = afsk_read_sample((phase >> 7) & (TABLE_SIZE - 1)); 197 | 198 | #ifdef DEBUG_AFSK 199 | Serial.print((uint16_t)s); 200 | Serial.print('/'); 201 | #endif 202 | 203 | #if PRE_EMPHASIS == 1 204 | if (phase_delta == PHASE_DELTA_1200) 205 | s = s / 2 + 64; 206 | #endif 207 | 208 | #ifdef DEBUG_AFSK 209 | Serial.print((uint16_t)s); 210 | Serial.print(' '); 211 | #endif 212 | 213 | afsk_fifo_in_safe(s); 214 | 215 | current_sample_in_baud += (1 << 8); 216 | if (current_sample_in_baud >= SAMPLES_PER_BAUD) { 217 | #ifdef DEBUG_AFSK 218 | Serial.println(); 219 | #endif 220 | packet_pos++; 221 | current_sample_in_baud -= SAMPLES_PER_BAUD; 222 | } 223 | } 224 | 225 | return true; // still working 226 | } 227 | 228 | // This is called at PLAYBACK_RATE Hz to load the next sample. 229 | AFSK_ISR 230 | { 231 | if (afsk_is_fifo_empty()) { 232 | if (go) { 233 | sample_overruns++; 234 | } 235 | } else { 236 | afsk_output_sample(afsk_fifo_out()); 237 | } 238 | afsk_clear_interrupt_flag(); 239 | } 240 | 241 | #ifdef DEBUG_MODEM 242 | void afsk_debug() 243 | { 244 | Serial.print("fifo overruns="); 245 | Serial.println(sample_overruns); 246 | 247 | sample_overruns = 0; 248 | } 249 | #endif 250 | -------------------------------------------------------------------------------- /trackuino/config.h: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #ifndef __CONFIG_H__ 19 | #define __CONFIG_H__ 20 | 21 | 22 | // -------------------------------------------------------------------------- 23 | // THIS IS THE TRACKUINO FIRMWARE CONFIGURATION FILE. YOUR CALLSIGN AND 24 | // OTHER SETTINGS GO HERE. 25 | // 26 | // NOTE: all pins are Arduino based, not the Atmega chip. Mapping: 27 | // http://www.arduino.cc/en/Hacking/PinMapping 28 | // -------------------------------------------------------------------------- 29 | 30 | 31 | // -------------------------------------------------------------------------- 32 | // APRS config (aprs.c) 33 | // -------------------------------------------------------------------------- 34 | 35 | // Set your callsign and SSID here. Common values for the SSID are 36 | // (from http://zlhams.wikidot.com/aprs-ssidguide): 37 | // 38 | // - Balloons: 11 39 | // - Cars: 9 40 | // - Home: 0 41 | // - IGate: 5 42 | #define S_CALLSIGN "MYCALL" 43 | #define S_CALLSIGN_ID 11 44 | 45 | // Destination callsign: APRS (with SSID=0) is usually okay. 46 | #define D_CALLSIGN "APRS" 47 | #define D_CALLSIGN_ID 0 48 | 49 | // Digipeating paths: 50 | // (read more about digipeating paths here: http://wa8lmf.net/DigiPaths/ ) 51 | // The recommended digi path for a balloon is WIDE2-1 or pathless. The default 52 | // is pathless. Uncomment the following two lines for WIDE2-1 path: 53 | #define DIGI_PATH1 "WIDE2" 54 | #define DIGI_PATH1_TTL 1 55 | 56 | // APRS comment: this goes in the comment portion of the APRS message. You 57 | // might want to keep this short. The longer the packet, the more vulnerable 58 | // it is to noise. 59 | #define APRS_COMMENT "Trackuino reminder: replace callsign with your own" 60 | 61 | 62 | // -------------------------------------------------------------------------- 63 | // AX.25 config (ax25.cpp) 64 | // -------------------------------------------------------------------------- 65 | 66 | // TX delay in milliseconds 67 | #define TX_DELAY 300 68 | 69 | // -------------------------------------------------------------------------- 70 | // Tracker config (trackuino.pde) 71 | // -------------------------------------------------------------------------- 72 | 73 | // APRS packets are slotted so that multiple trackers can be used without 74 | // them stepping on one another. The transmission times are governed by 75 | // the formula: 76 | // 77 | // APRS_SLOT (seconds) + n * APRS_PERIOD (seconds) 78 | // 79 | // When launching multiple balloons, use the same APRS_PERIOD in all balloons 80 | // and set APRS_SLOT so that the packets are spaced equally in time. 81 | // Eg. for two balloons and APRS_PERIOD = 60, set APRS_SLOT to 0 and 30, 82 | // respectively. The first balloon will transmit at 00:00:00, 00:01:00, 83 | // 00:02:00, etc. and the second balloon will transmit at 00:00:30, 00:01:30, 84 | // 00:02:30, etc. 85 | #define APRS_SLOT 0 // seconds. -1 disables slotted transmissions 86 | #define APRS_PERIOD 60 // seconds 87 | 88 | // GPS baud rate (in bits per second). This is also the baud rate at which 89 | // debug data will be printed out the serial port. 90 | #define GPS_BAUDRATE 9600 91 | 92 | 93 | // -------------------------------------------------------------------------- 94 | // Modem config (afsk.cpp) 95 | // -------------------------------------------------------------------------- 96 | 97 | // AUDIO_PIN is the audio-out pin. The audio is generated by timer 2 using 98 | // PWM, so the only two options are pins 3 and 11. 99 | // Pin 11 doubles as MOSI, so I suggest using pin 3 for PWM and leave 11 free 100 | // in case you ever want to interface with an SPI device. 101 | #define AUDIO_PIN 3 102 | 103 | // Pre-emphasize the 2200 tone by 6 dB. This is actually done by 104 | // de-emphasizing the 1200 tone by 6 dB and it might greatly improve 105 | // reception at the expense of poorer FM deviation, which translates 106 | // into an overall lower amplitude of the received signal. 1 = yes, 0 = no. 107 | #define PRE_EMPHASIS 1 108 | 109 | // -------------------------------------------------------------------------- 110 | // Radio config (radio_hx1.cpp) 111 | // -------------------------------------------------------------------------- 112 | 113 | // This is the PTT pin 114 | #define PTT_PIN 4 115 | 116 | // -------------------------------------------------------------------------- 117 | // Sensors config (sensors.cpp) 118 | // -------------------------------------------------------------------------- 119 | 120 | // Most of the sensors.cpp functions use internal reference voltages (either 121 | // AVCC or 1.1V). If you want to use an external reference, you should 122 | // uncomment the following line: 123 | // 124 | // #define USE_AREF 125 | // 126 | // BEWARE! If you hook up an external voltage to the AREF pin and 127 | // accidentally set the ADC to any of the internal references, YOU WILL 128 | // FRY YOUR AVR. 129 | // 130 | // It is always advised to connect the AREF pin through a pull-up resistor, 131 | // whose value is defined here in ohms (set to 0 if no pull-up): 132 | // 133 | #define AREF_PULLUP 4700 134 | // 135 | // Since there is already a 32K resistor at the ADC pin, the actual 136 | // voltage read will be VREF * 32 / (32 + AREF_PULLUP) 137 | // 138 | // Read more in the Arduino reference docs: 139 | // http://arduino.cc/en/Reference/AnalogReference?from=Reference.AREF 140 | 141 | // Pin mappings for the internal / external temperature sensors. VS refers 142 | // to (arduino) digital pins, whereas VOUT refers to (arduino) analog pins. 143 | #define INTERNAL_LM60_VS_PIN 6 144 | #define INTERNAL_LM60_VOUT_PIN 0 145 | #define EXTERNAL_LM60_VS_PIN 7 146 | #define EXTERNAL_LM60_VOUT_PIN 1 147 | 148 | // Units for temperature sensors (Added by: Kyle Crockett) 149 | // 1 = Celsius, 2 = Kelvin, 3 = Fahrenheit 150 | #define TEMP_UNIT 1 151 | 152 | // Calibration value in the units selected. Use integer only. 153 | #define CALIBRATION_VAL 0 154 | 155 | // Resistors divider for the voltage meter (ohms) 156 | #define VMETER_R1 10000 157 | #define VMETER_R2 3300 158 | 159 | // Voltage meter analog pin 160 | #define VMETER_PIN 2 161 | 162 | // -------------------------------------------------------------------------- 163 | // Buzzer config (buzzer.cpp) 164 | // -------------------------------------------------------------------------- 165 | 166 | // Type of buzzer (0=active, 1=passive). An active buzzer is driven by a 167 | // DC voltage. A passive buzzer needs a PWM signal. 168 | #define BUZZER_TYPE 0 169 | 170 | // When using a passive buzzer, specify the PWM frequency here. Choose one 171 | // that maximizes the volume according to the buzzer's datasheet. Not all 172 | // the frequencies are valid, check out the buzzer_*.cpp code. On Arduino, 173 | // it must be between L and 65535, where L = F_CPU / 65535 and F_CPU is the 174 | // clock rate in hertzs. For 16 MHz Arduinos, this gives a lower limit of 175 | // 245 Hz. 176 | #define BUZZER_FREQ 895 // Hz 177 | 178 | // These are the number of seconds the buzzer will stay on/off alternately 179 | #define BUZZER_ON_TIME 1 // secs 180 | #define BUZZER_OFF_TIME 2 // secs 181 | 182 | // This option disables the buzzer above BUZZER_ALTITUDE meters. This is a 183 | // float value, so make it really high (eg. 1000000.0 = 1 million meters) 184 | // if you want it to never stop buzzing. 185 | #define BUZZER_ALTITUDE 3000.0 // meters (1 ft = 0.3048 m) 186 | 187 | // The options here are pin 9 or 10 188 | #define BUZZER_PIN 9 189 | 190 | // -------------------------------------------------------------------------- 191 | // Debug 192 | // -------------------------------------------------------------------------- 193 | 194 | // This is the LED pin (13 on Arduinos). The LED will be on while the AVR is 195 | // running and off while it's sleeping, so its brightness gives an indication 196 | // of the CPU activity. 197 | #define LED_PIN 13 198 | 199 | // Debug info includes printouts from different modules to aid in testing and 200 | // debugging. 201 | // 202 | // Some of the DEBUG modes will cause invalid modulation, so do NOT forget 203 | // to turn them off when you put this to real use. 204 | // 205 | // Particularly the DEBUG_AFSK will print every PWM sample out the serial 206 | // port, causing extreme delays in the actual AFSK transmission. 207 | // 208 | // 1. To properly receive debug information, only connect the Arduino RX pin 209 | // to the GPS TX pin, and leave the Arduino TX pin disconnected. 210 | // 211 | // 2. On the serial monitor, set the baudrate to GPS_BAUDRATE (above), 212 | // usually 9600. 213 | // 214 | // 3. When flashing the firmware, disconnect the GPS from the RX pin or you 215 | // will get errors. 216 | 217 | // #define DEBUG_GPS // GPS sentence dump and checksum validation 218 | // #define DEBUG_AX25 // AX.25 frame dump 219 | // #define DEBUG_MODEM // Modem ISR overrun and profiling 220 | // #define DEBUG_AFSK // AFSK (modulation) output 221 | // #define DEBUG_RESET // AVR reset 222 | // #define DEBUG_SENS // Sensors 223 | 224 | 225 | #endif 226 | 227 | -------------------------------------------------------------------------------- /trackuino/gps.cpp: -------------------------------------------------------------------------------- 1 | /* trackuino copyright (C) 2010 EA5HAV Javi 2 | * 3 | * This program is free software; you can redistribute it and/or 4 | * modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation; either version 2 6 | * of the License, or (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | */ 17 | 18 | #include "config.h" 19 | #include "gps.h" 20 | #if (ARDUINO + 1) >= 100 21 | # include 22 | #else 23 | # include 24 | #endif 25 | #include 26 | #include 27 | 28 | // Module declarations 29 | static void parse_sentence_type(const char * token); 30 | static void parse_time(const char *token); 31 | static void parse_status(const char *token); 32 | static void parse_lat(const char *token); 33 | static void parse_lat_hemi(const char *token); 34 | static void parse_lon(const char *token); 35 | static void parse_lon_hemi(const char *token); 36 | static void parse_speed(const char *token); 37 | static void parse_course(const char *token); 38 | static void parse_altitude(const char *token); 39 | 40 | // Module types 41 | typedef void (*t_nmea_parser)(const char *token); 42 | 43 | enum t_sentence_type { 44 | SENTENCE_UNK, 45 | SENTENCE_GGA, 46 | SENTENCE_RMC 47 | }; 48 | 49 | 50 | // Module constants 51 | static const t_nmea_parser unk_parsers[] = { 52 | parse_sentence_type, // $GPxxx 53 | }; 54 | 55 | static const t_nmea_parser gga_parsers[] = { 56 | NULL, // $GPGGA 57 | parse_time, // Time 58 | NULL, // Latitude 59 | NULL, // N/S 60 | NULL, // Longitude 61 | NULL, // E/W 62 | NULL, // Fix quality 63 | NULL, // Number of satellites 64 | NULL, // Horizontal dilution of position 65 | parse_altitude, // Altitude 66 | NULL, // "M" (mean sea level) 67 | NULL, // Height of GEOID (MSL) above WGS84 ellipsoid 68 | NULL, // "M" (mean sea level) 69 | NULL, // Time in seconds since the last DGPS update 70 | NULL // DGPS station ID number 71 | }; 72 | 73 | static const t_nmea_parser rmc_parsers[] = { 74 | NULL, // $GPRMC 75 | parse_time, // Time 76 | parse_status, // A=active, V=void 77 | parse_lat, // Latitude, 78 | parse_lat_hemi, // N/S 79 | parse_lon, // Longitude 80 | parse_lon_hemi, // E/W 81 | parse_speed, // Speed over ground in knots 82 | parse_course, // Track angle in degrees (true) 83 | NULL, // Date (DDMMYY) 84 | NULL, // Magnetic variation 85 | NULL // E/W 86 | }; 87 | 88 | static const int NUM_OF_UNK_PARSERS = (sizeof(unk_parsers) / sizeof(t_nmea_parser)); 89 | static const int NUM_OF_GGA_PARSERS = (sizeof(gga_parsers) / sizeof(t_nmea_parser)); 90 | static const int NUM_OF_RMC_PARSERS = (sizeof(rmc_parsers) / sizeof(t_nmea_parser)); 91 | 92 | // Module variables 93 | static t_sentence_type sentence_type = SENTENCE_UNK; 94 | static bool at_checksum = false; 95 | static unsigned char our_checksum = '$'; 96 | static unsigned char their_checksum = 0; 97 | static char token[16]; 98 | static int num_tokens = 0; 99 | static unsigned int offset = 0; 100 | static bool active = false; 101 | static char gga_time[7] = "", rmc_time[7] = ""; 102 | static char new_time[7]; 103 | static uint32_t new_seconds; 104 | static float new_lat; 105 | static float new_lon; 106 | static char new_aprs_lat[9]; 107 | static char new_aprs_lon[10]; 108 | static float new_course; 109 | static float new_speed; 110 | static float new_altitude; 111 | 112 | // Public (extern) variables, readable from other modules 113 | char gps_time[7]; // HHMMSS 114 | uint32_t gps_seconds = 0; // seconds after midnight 115 | float gps_lat = 0; 116 | float gps_lon = 0; 117 | char gps_aprs_lat[9]; 118 | char gps_aprs_lon[10]; 119 | float gps_course = 0; 120 | float gps_speed = 0; 121 | float gps_altitude = 0; 122 | 123 | // Module functions 124 | unsigned char from_hex(char a) 125 | { 126 | if (a >= 'A' && a <= 'F') 127 | return a - 'A' + 10; 128 | else if (a >= 'a' && a <= 'f') 129 | return a - 'a' + 10; 130 | else if (a >= '0' && a <= '9') 131 | return a - '0'; 132 | else 133 | return 0; 134 | } 135 | 136 | void parse_sentence_type(const char *token) 137 | { 138 | if (strcmp(token+3, "GGA") == 0) { 139 | sentence_type = SENTENCE_GGA; 140 | } else if (strcmp(token+3, "RMC") == 0) { 141 | sentence_type = SENTENCE_RMC; 142 | } else { 143 | sentence_type = SENTENCE_UNK; 144 | } 145 | } 146 | 147 | void parse_time(const char *token) 148 | { 149 | // Time can have decimals (fractions of a second), but we only take HHMMSS 150 | strncpy(new_time, token, 6); 151 | // Terminate string 152 | new_time[6] = '\0'; 153 | 154 | new_seconds = 155 | ((new_time[0] - '0') * 10 + (new_time[1] - '0')) * 60 * 60UL + 156 | ((new_time[2] - '0') * 10 + (new_time[3] - '0')) * 60 + 157 | ((new_time[4] - '0') * 10 + (new_time[5] - '0')); 158 | } 159 | 160 | void parse_status(const char *token) 161 | { 162 | // "A" = active, "V" = void. We shoud disregard void sentences 163 | if (strcmp(token, "A") == 0) 164 | active = true; 165 | else 166 | active = false; 167 | } 168 | 169 | void parse_lat(const char *token) 170 | { 171 | // Parses latitude in the format "DD" + "MM" (+ ".M{...}M") 172 | char degs[3]; 173 | if (strlen(token) >= 4) { 174 | degs[0] = token[0]; 175 | degs[1] = token[1]; 176 | degs[2] = '\0'; 177 | new_lat = atof(degs) + atof(token + 2) / 60; 178 | } 179 | // APRS-ready latitude 180 | strncpy(new_aprs_lat, token, 7); 181 | new_aprs_lat[7] = '\0'; 182 | } 183 | 184 | void parse_lat_hemi(const char *token) 185 | { 186 | if (token[0] == 'S') 187 | new_lat = -new_lat; 188 | new_aprs_lat[7] = token[0]; 189 | new_aprs_lon[8] = '\0'; 190 | } 191 | 192 | void parse_lon(const char *token) 193 | { 194 | // Longitude is in the format "DDD" + "MM" (+ ".M{...}M") 195 | char degs[4]; 196 | if (strlen(token) >= 5) { 197 | degs[0] = token[0]; 198 | degs[1] = token[1]; 199 | degs[2] = token[2]; 200 | degs[3] = '\0'; 201 | new_lon = atof(degs) + atof(token + 3) / 60; 202 | } 203 | // APRS-ready longitude 204 | strncpy(new_aprs_lon, token, 8); 205 | new_aprs_lon[8] = '\0'; 206 | } 207 | 208 | void parse_lon_hemi(const char *token) 209 | { 210 | if (token[0] == 'W') 211 | new_lon = -new_lon; 212 | new_aprs_lon[8] = token[0]; 213 | new_aprs_lon[9] = '\0'; 214 | } 215 | 216 | void parse_speed(const char *token) 217 | { 218 | new_speed = atof(token); 219 | } 220 | 221 | void parse_course(const char *token) 222 | { 223 | new_course = atof(token); 224 | } 225 | 226 | void parse_altitude(const char *token) 227 | { 228 | new_altitude = atof(token); 229 | } 230 | 231 | 232 | // 233 | // Exported functions 234 | // 235 | void gps_setup() { 236 | strcpy(gps_time, "000000"); 237 | strcpy(gps_aprs_lat, "0000.00N"); 238 | strcpy(gps_aprs_lon, "00000.00E"); 239 | } 240 | 241 | void gps_reset_parser() { 242 | at_checksum = false; // CR/LF signals the end of the checksum 243 | our_checksum = '$'; // Reset checksums 244 | their_checksum = 0; 245 | offset = 0; // Prepare for the next incoming sentence 246 | num_tokens = 0; 247 | sentence_type = SENTENCE_UNK; 248 | } 249 | 250 | bool gps_decode(char c) 251 | { 252 | int ret = false; 253 | 254 | switch(c) { 255 | case '\r': 256 | break; 257 | case '\n': 258 | // End of sentence 259 | 260 | if (num_tokens && our_checksum == their_checksum) { 261 | #ifdef DEBUG_GPS 262 | Serial.print(" (OK!) "); 263 | Serial.print(millis()); 264 | #endif 265 | // Return a valid position only when we've got two rmc and gga 266 | // messages with the same timestamp. 267 | switch (sentence_type) { 268 | case SENTENCE_UNK: 269 | break; // Keeps gcc happy 270 | case SENTENCE_GGA: 271 | strcpy(gga_time, new_time); 272 | break; 273 | case SENTENCE_RMC: 274 | strcpy(rmc_time, new_time); 275 | break; 276 | } 277 | 278 | // Valid position scenario: 279 | // 280 | // 1. The timestamps of the two previous GGA/RMC sentences must match. 281 | // 282 | // 2. We just processed a known (GGA/RMC) sentence. Suppose the 283 | // contrary: after starting up this module, gga_time and rmc_time 284 | // are both equal (they're both initialized to ""), so (1) holds 285 | // and we wrongly report a valid position. 286 | // 287 | // 3. The GPS has a valid fix. For some reason, the Venus 634FLPX 288 | // reports 24 deg N, 121 deg E (the middle of Taiwan) until a valid 289 | // fix is acquired: 290 | // 291 | // $GPGGA,120003.000,2400.0000,N,12100.0000,E,0,00,0.0,0.0,M,0.0,M,,0000*69 (OK!) 292 | // $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30 (OK!) 293 | // $GPRMC,120003.000,V,2400.0000,N,12100.0000,E,000.0,000.0,280606,,,N*78 (OK!) 294 | // $GPVTG,000.0,T,,M,000.0,N,000.0,K,N*02 (OK!) 295 | 296 | if (sentence_type != SENTENCE_UNK && // Known sentence? 297 | strcmp(gga_time, rmc_time) == 0 && // RMC/GGA times match? 298 | active) { // Valid fix? 299 | // Atomically merge data from the two sentences 300 | strcpy(gps_time, new_time); 301 | gps_seconds = new_seconds; 302 | gps_lat = new_lat; 303 | gps_lon = new_lon; 304 | strcpy(gps_aprs_lat, new_aprs_lat); 305 | strcpy(gps_aprs_lon, new_aprs_lon); 306 | gps_course = new_course; 307 | gps_speed = new_speed; 308 | gps_altitude = new_altitude; 309 | ret = true; 310 | #ifdef DEBUG_GPS 311 | Serial.print(" ACCEPT"); 312 | #endif 313 | } 314 | } else { 315 | #ifdef DEBUG_GPS 316 | Serial.print(" (BAD!) "); 317 | Serial.print(millis()); 318 | #endif 319 | } 320 | 321 | #ifdef DEBUG_GPS 322 | if (num_tokens) 323 | Serial.println(); 324 | #endif 325 | 326 | gps_reset_parser(); 327 | break; 328 | 329 | case '*': 330 | // Handle as ',', but prepares to receive checksum (ie. do not break) 331 | at_checksum = true; 332 | our_checksum ^= c; 333 | 334 | case ',': 335 | // Process token 336 | token[offset] = '\0'; 337 | our_checksum ^= c; // Checksum the ',', undo the '*' 338 | 339 | // Parse token 340 | switch (sentence_type) { 341 | case SENTENCE_UNK: 342 | if (num_tokens < NUM_OF_UNK_PARSERS && unk_parsers[num_tokens]) 343 | unk_parsers[num_tokens](token); 344 | break; 345 | case SENTENCE_GGA: 346 | if (num_tokens < NUM_OF_GGA_PARSERS && gga_parsers[num_tokens]) 347 | gga_parsers[num_tokens](token); 348 | break; 349 | case SENTENCE_RMC: 350 | if (num_tokens < NUM_OF_RMC_PARSERS && rmc_parsers[num_tokens]) 351 | rmc_parsers[num_tokens](token); 352 | break; 353 | } 354 | 355 | // Prepare for next token 356 | num_tokens++; 357 | offset = 0; 358 | #ifdef DEBUG_GPS 359 | Serial.print(c); 360 | #endif 361 | break; 362 | 363 | default: 364 | // Any other character 365 | if (at_checksum) { 366 | // Checksum value 367 | their_checksum = their_checksum * 16 + from_hex(c); 368 | } else { 369 | // Regular NMEA data 370 | if (offset < 15) { // Avoid buffer overrun (tokens can't be > 15 chars) 371 | token[offset] = c; 372 | offset++; 373 | our_checksum ^= c; 374 | } 375 | } 376 | #ifdef DEBUG_GPS 377 | Serial.print(c); 378 | #endif 379 | } 380 | return ret; 381 | } 382 | 383 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | --------------------------------------------------------------------------------