; Open GPS Tracker firmware ; Version 0.19B 2009/01/09 ; Mike Ingle (email: mike at opengpstracker dot org) ; http://www.opengpstracker.org ; This is open source software. ; ; If you are upgrading from build 0.14, you must change the phone configuration: ; Message/Options/Memory Meter/Select SMS Memory/Phone First ; ; For ATTINY84 or ATMEGA88 or ATMEGA168 AVR ; Tyco A1035 GPS or AARLOGIC GPS 3A ; Motorola C168i or Telit GC864 phone ; Set MCU to run at 1 MHz (CKDIV8 fuse) ; Commands: ; ; SETSPEED ; speed limit or 0 for none - units ; minimum speed to accept as moving - tenths of a unit ; minimum speed to accept as moving on first try - tenths of a unit ; SETTRACK ; stopped fix interval - seconds ; stopped notify delay - intervals ; blocked fix interval - seconds ; blocked notify delay - intervals ; moving fix interval - seconds ; moving notify frequency - intervals ; minimum displacement for MOVED alert ; SETPOWER ; powersave phone off interval - seconds ; powersave phone on interval - seconds ; four-sat fix wait time (before accepting three-sat fix) - seconds ; fix wait time (before giving up and reporting no fix) - seconds ; blocked fix wait time (shorter fix wait when no signal available) - seconds ; For I/O, the bytes and masks are decimal numbers representing the bits ; of the I/O ports, so port pins 0, 1, 2, 3 correspond to 1, 2, 4, 8, etc. ; The ATTINY84 uses PORTA pins 3-7 for digital I/O and analog measurement. ; The ATMEGA88 uses PORTB for digital I/O and the dedicated analog inputs. ; SETIO input-output-selection default-output-value ; ; OUTPUT output-byte ; Returns INPUT value ; ; INPUT ; Returns: INPUT value ; ; ALERT alert-on-low-mask alert-on-high-mask ; Enables alerting when bits change value (0 disables) ; ; MEASURE ; Returns: ; MEASURE 1 2 3 4 5 6 ; These are the analog ins on the MEGA88. ; On the TINY84 it is pins A2-A7 and the temperature sensor. ; OUTPULSE output-byte [optional duration in 1/4 seconds] ; Outputs new value, waits (default 1 second) and outputs old value again ; SETNAME tracker-name ; SETPASSWORD newpassword newpassword ; SETADDRESS phone-number optional-email-address ; SALOCATE phone-number optional-email-address ; LOCATE ; STATUS ; TRACKON ; TRACKOFF ; POWERSAVE ; POWERON ; REBOOT ; REINIT ; ; Blink codes: ; 11 = phone polled ; 12 = send message failed ; 13 = phone poll failed ; 14 = no phone number defined ; 21 = invalid password ; 31 = power on or reset ; 32 = watchdog reset ; 33 = EEPROM initialized from defaults ; 34 = remove jumper to reinitialize EEPROM ; ; Configuring these options: ; There is no checking to make sure you give a consistent set of options. ; You can produce a faulty binary by enabling incompatible options. ; GC864 power and control is only supported on a ATMEGAX8 ; Car security is only supported on a ATMEGAX8 ; Car security and remote I/O do not coexist ; RESET_PHONE_PERIODICALLY is only for a C168i ; and GC864 power and control is only for a GC864 ; ; Car security mode commands and pinouts ; HONK n - honk horn and flash lights n times, default 4 ; CARDISABLE - disable the starter ; CARENABLE - enable the starter ; CARUNLOCK - unlock the door ; ; ATMEGA88 pinouts ; D0 - INPUT - RX in from phone/module ; D1 - OUTPUT - TX out to phone/module ; D2 - INPUT - RX in from GPS ; D3 and D4 - OUTPUT - two-color status LED, D3 positive for red light ; D5 - OUTPUT - GPS power out ; B6 - OUTPUT - GC864 ON/OFF toggle ; B7 - OUTPUT - GC864 RESET input ; D6 - INPUT - PWRMON input from GC864 module ; B2 - INPUT - ALARM1 trigger input ; B3 - INPUT - ALARM2 trigger input ; B4 - INPUT - Power Lost input ; B0 - OUTPUT - Starter Disable output ; B1 - OUTPUT - Horn/Lights output ; B5 - OUTPUT - Unlock output ; C0 - OUTPUT - Master enable output ; Port B - digital I/O (non car security mode) ; ; ATTINY84 pinouts ; A0 - INPUT - RX in from phone/module ; A1 - OUTPUT - TX out to phone/module ; A2 - INPUT - RX in from GPS ; B0 and B1 - OUTPUT - two-color status LED, B0 positive for red light ; B2 - OUTPUT - GPS power out ; Must define ONE and ONLY ONE of SPEED_IN_KPH, SPEED_IN_MPH, or SPEED_IN_KNOTS ;#define SPEED_IN_KPH = 1 #define SPEED_IN_MPH = 1 ;#define SPEED_IN_KNOTS = 1 ; Must define ONE and ONLY ONE of ALT_IN_FEET or ALT_IN_METERS #define ALT_IN_FEET = 1 ;#define ALT_IN_METERS = 1 ; Serial debug will copy phone interaction to TX_OUT_TO_DEBUG ; Does not coexist with the remote I/O option. ;#define SERIAL_DEBUG 1 ; Debug message count will keep track of messages sent and output in status page ;#define DEBUG_MESSAGE_COUNT_ENABLE 1 ; Keeps invalid incoming messages in the phone. This disables reading of REC READ ; folder. It is only for debugging. I put it here to track down a message bounce problem. ;#define DEBUG_KEEP_INVALID_MESSAGES 1 ; Add error codes to WDR_COUNT for send message failures. ;#define DEBUG_SEND_MESSAGES 1 ; Reset phone after every PHONE_RESET_INTERVAL interactions and for power on ; Required for C168i and GoPhone service ; Turn off for other phones #define RESET_PHONE_PERIODICALLY 1 ; If not resetting the phone, should we send CFUN=1 at startup? ;#define PHONE_CFUN1_AT_STARTUP 1 ; Most define ONE and ONLY ONE phone type #define PHONE_TYPE_C168I 1 ;#define PHONE_TYPE_WMOD2 1 ;#define PHONE_TYPE_SAMSUNG_317 1 ;#define PHONE_TYPE_TELIT_GC864 1 ; For Samsung phone, connect RTS to CTS (brown and red on my cable) ; to get AT commands working. And no, I do not know how to make the light ; stop flashing on the Samsung. ; The Wavecom WMOD2 is RS-232 level and requires a level converter. ; It only works as 9600 baud. ; Must define ONE and ONLY ONE MCU type #define MCU_TYPE_ATTINY84 1 ;#define MCU_TYPE_ATMEGA88 1 ;#define MCU_TYPE_ATMEGA168 1 ; Define this to enable the I/O options (INPUT, OUTPUT, SETIO, MEASURE) ;#define OPTION_REMOTE_IO 1 ; If you enable this and set the defaults, alerts will be enabled at boot time ; Note these masks are not left-shifted for the ATTINY84 and refer to actual pins ;#define OPTION_REMOTE_IO_AUTOENABLE_ALERTS 1 .equ DEFAULT_IO_ALERT_ON_LOW_MASK = 0 .equ DEFAULT_IO_ALERT_ON_HIGH_MASK = 0 ; Define this option to enable textual INPUT and ALERT #define OPTION_REMOTE_IO_TEXT 1 ; Define this to enable the car alarm mode (do not define remote I/O above) ;#define OPTION_CAR_SECURITY 1 ; Define this to have the AVR control power and reset to the GC864 module ; Need to make sure there are no pin conflicts with remote I/O ; Only configured for the ATMEGA88 right now ;#define OPTION_GC864_POWER_AND_RESET 1 ; This does not work yet, so don't use it. ; Define if optional components are installed to measure tracker battery voltage ;#define MEASURE_TRACKER_BATTERY 1 #ifdef MCU_TYPE_ATTINY84 .include "tn84def.inc" #define TRACKER_BATTERY_ADC_INPUT 3 #endif #ifdef MCU_TYPE_ATMEGA88 .include "m88def.inc" #define TRACKER_BATTERY_ADC_INPUT 5 #define MCU_TYPE_ATMEGAX8 1 #endif #ifdef MCU_TYPE_ATMEGA168 .include "m168def.inc" #define TRACKER_BATTERY_ADC_INPUT 5 #define MCU_TYPE_ATMEGAX8 1 #endif #ifdef MCU_TYPE_ATTINY84 #ifdef OPTION_REMOTE_IO #define ATTINY84_WITH_IO 1 #endif #endif #ifdef OPTION_REMOTE_IO #define OPTION_REMOTE_IO_OR_CAR_SECURITY 1 #endif #ifdef OPTION_CAR_SECURITY #define OPTION_REMOTE_IO_OR_CAR_SECURITY 1 #endif ; If using Aarlogic GPS 3A module, run at 9600 baud ; Aarlogic module can be set to 4800 but does not retain setting, so use default 9600 #ifdef PHONE_TYPE_WMOD2 .equ BAUD_RATE_COUNTER = 104 ; 9600 baud .equ GPS_BAUD_RATE_COUNTER = 208 ; 4800 baud #else ;.equ BAUD_RATE_COUNTER = 104 ; 9600 baud .equ BAUD_RATE_COUNTER = 208 ; 4800 baud #endif .equ INIT_RECEIVE_TIMEOUT = 8 ; short timeout for ATE0 (2 seconds) .equ DEFAULT_RECEIVE_TIMEOUT = 20 ; timeout for most commands (5 seconds) .equ SMS_SEND_RECEIVE_TIMEOUT = 120 ; timeout for SMS SEND (24 seconds) .equ DEFAULT_PHONE_POLL_INTERVAL = 900 ; default phone poll interval (not tracking) in seconds (15 minutes) .equ DEFAULT_FOUR_SAT_WAIT_TIME = 18 ; 72 seconds (x4) .equ DEFAULT_GPS_FIX_WAIT_TIME = 34 ; 136 seconds (x4) .equ DEFAULT_BLOCKED_GPS_FIX_WAIT_TIME = 24 ; 96 seconds .equ DEFAULT_SPEED_LIMIT = 0 ; disabled .equ DEFAULT_TRACK_STOPPED_FIX_INTERVAL = 120 ; two minutes .equ DEFAULT_TRACK_STOPPED_NOTIFY_DELAY = 2 ; 2 poll intervals .equ DEFAULT_TRACK_BLOCKED_FIX_INTERVAL = 600 ; ten minutes .equ DEFAULT_TRACK_BLOCKED_NOTIFY_DELAY = 2 ; 2 poll intervals .equ DEFAULT_TRACK_MOVING_FIX_INTERVAL = 120 ; two minutes .equ DEFAULT_TRACK_MOVING_NOTIFY_FREQ = 5 ; 5 poll intervals .equ DEFAULT_POWERSAVE_PHONE_OFF_INTERVAL = 3600 ; one hour .equ DEFAULT_POWERSAVE_PHONE_ON_INTERVAL = 600 ; 10 minutes .equ DEFAULT_TRACK_MIN_DISPLACEMENT = 200 ; 0.2 minute of lat/lon .equ DEFAULT_GPS_MOVING_THRESHOLD = 20 ; 2 or more units reported = moving .equ DEFAULT_GPS_MOVING_RETRY_THRESHOLD = 100 ; if under 10 units, double check speed .equ GPS_DATASTREAM_WAIT_TIME = 60 ; 15 seconds .equ GPS_LINES_AFTER_FIX = 10 ; how many more lines to wait for after fix valid .equ PHONE_RESET_INTERVAL = 100 ; reset phone every N polls, after message received .equ PHONE_RESET_WAKEUP_DELAY = 45 ; time in seconds to wait for the phone to power on #ifdef PHONE_TYPE_WMOD2 .equ PHONE_MAX_CHECKSUM_LENGTH = 159 ; largest message phone will store #else #ifdef PHONE_TYPE_TELIT_GC864 .equ PHONE_MAX_CHECKSUM_LENGTH = 160 ; largest message phone will store #define PHONE_SUPPRESS_OVERLONG_MESSAGE 1 #define PHONE_NEEDS_DELAY 1 #else .equ PHONE_MAX_CHECKSUM_LENGTH = 160 ; largest message phone will store #endif #endif #ifdef PHONE_TYPE_SAMSUNG_317 #define PHONE_NEEDS_DELAY 1 #endif ; Units conversion factors (from HP50G calculator) .equ CF_KNOT_MPH = 37709 ; KNOT * 2 before conversion .equ CF_KNOT_KPH = 60686 ; KNOT * 2 before conversion .equ CF_M_FT = 53753 ; M * 4 before conversion #ifdef MCU_TYPE_ATTINY84 .equ TX_OUT_TO_PHONE = PORTA1 .equ RX_IN_FROM_PHONE = PORTA0 .equ RX_IN_FROM_GPS = PORTA2 .equ TX_OUT_TO_DEBUG = PORTA7 .equ REINIT_CHECK_IN = PORTA4 .equ REINIT_CHECK_OUT = PORTA6 .equ PORT_SERIAL = PORTA .equ PIN_SERIAL = PINA .equ DDR_SERIAL = DDRA .equ DDR_REINIT = DDRA .equ PIN_REINIT = PINA .equ PORT_REINIT = PORTA .equ PORT_LED_POWER = PORTB .equ LED_OUT_RED = PORTB0 .equ LED_OUT_GREEN = PORTB1 .equ GPS_POWER_OUT = PORTB2 #endif #ifdef MCU_TYPE_ATMEGAX8 .equ TX_OUT_TO_PHONE = PORTD1 .equ RX_IN_FROM_PHONE = PORTD0 .equ RX_IN_FROM_GPS = PORTD2 .equ TX_OUT_TO_DEBUG = PORTD7 .equ REINIT_CHECK_IN = PORTB3 .equ REINIT_CHECK_OUT = PORTB5 .equ PORT_SERIAL = PORTD .equ PIN_SERIAL = PIND .equ DDR_SERIAL = DDRD .equ DDR_REINIT = DDRB .equ PIN_REINIT = PINB .equ PORT_REINIT = PORTB .equ PORT_LED_POWER = PORTD .equ LED_OUT_RED = PORTD3 .equ LED_OUT_GREEN = PORTD4 .equ GPS_POWER_OUT = PORTD5 .equ DDR_GC864_POWER = DDRB .equ PIN_GC864_PWRMON = PIND .equ PORT_GC864_POWER = PORTB .equ GC864_POWER_OUT = PORTB6 .equ GC864_RESET_OUT = PORTB7 .equ GC864_PWRMON_IN = PORTD6 .equ PIN_ALARM = PINB .equ PORT_ALARM = PORTB .equ DDR_ALARM = DDRB .equ ALARM_TRIGGER1_IN = PORTB2 .equ ALARM_TRIGGER2_IN = PORTB3 .equ ALARM_POWER_LOST_IN = PORTB4 .equ ALARM_STARTER_DISABLE_OUT = PORTB0 .equ ALARM_HORN_OUT = PORTB1 .equ ALARM_UNLOCK_OUT = PORTB5 .equ ALARM_MASTER_ENABLE = PORTC0 #endif #ifdef OPTION_GC864_POWER_AND_RESET #ifdef OPTION_CAR_SECURITY ; POWER AND RESET + CAR SECURITY .equ DEFAULT_IO_DDR = (1< ; Field number starts with 0 meaning first field. Put FF after last field. ; NMEA Checksum goes from right after $ to before * ; Non-NMEA checksum is whole line excluding newline ; NMEA delimiter is a comma and end of line is * then two checksum digits ; Command line delimiter is normally a space and end of line is a CR ; Set FLAG_PARSE_NMEA for NMEA mode, clear it for command line mode ; Timeout sets T flag and aborts. PARSE_NMEA_OR_COMMAND_LINE: clr READ_FIELD ; current field clr PAT ; use as a zero for writing into memory clr CHECKSUM ; calculated in both modes, VERIFY_CHECKSUM only in NMEA mode cbr FLAG_REGISTER,1<10, do nothing. =10, send start bit. <10, send data. breq SERIAL_SEND_START_BIT brcc SERIAL_DEC_AND_RET SERIAL_SEND_DATA_BIT: ror SERIAL_DATA ; drop low bit into carry flag, 1 from carry into high bit SERIAL_SEND_START_BIT: in SERIAL_SCRATCH,PORT_SERIAL ; IN and OR do not change carry flag or SERIAL_SCRATCH,SERIAL_PORT ; sets to 1 the bit for the selected port brcs SERIAL_SEND_DATA_ONE sub SERIAL_SCRATCH,SERIAL_PORT ; If it's a 0, set bit to zero in output SERIAL_SEND_DATA_ONE: out PORT_SERIAL,SERIAL_SCRATCH SERIAL_DEC_AND_RET: dec SERIAL_COUNT brne SERIAL_SEND_NOT_DONE ; serial send done #ifdef MCU_TYPE_ATTINY84 out TCCR1B,REG_ZERO ; stop the serial clock #endif #ifdef MCU_TYPE_ATMEGAX8 sts TCCR1B,REG_ZERO ; stop the serial clock #endif SERIAL_SEND_NOT_DONE: out SREG,SERIAL_INTERRUPT_SREG reti ; ; Interrupt for the first bit (long delay after start bit) SERIAL_RECEIVE_INTERRUPT: in SERIAL_SCRATCH,PIN_SERIAL ; get the register and SERIAL_SCRATCH,SERIAL_PORT ; isolate active input pin neg SERIAL_SCRATCH ; this sets carry flag unless register is zero ror SERIAL_DATA ; roll the bit from carry flag into shift register dec SERIAL_COUNT brne SERIAL_RECEIVE_RETI ; last bit? ; last bit #ifdef MCU_TYPE_ATTINY84 out TCCR1B,REG_ZERO ; stop the serial clock #endif #ifdef MCU_TYPE_ATMEGAX8 sts TCCR1B,REG_ZERO ; stop the serial clock #endif push ZH ; borrow Z pointer push ZL ldi ZH,1 ; buffer is 0x100-0x1ff mov ZL,SERIAL_POINTER st Z,SERIAL_DATA inc SERIAL_POINTER ; bump pointer after saving; pointer indicates next byte pop ZL pop ZH #ifdef MCU_TYPE_ATTINY84 #ifdef OPTION_REMOTE_IO_OR_CAR_SECURITY lds SERIAL_SCRATCH,IO_ALERT_MASK or SERIAL_SCRATCH,SERIAL_PORT out PCMSK0,SERIAL_SCRATCH ; enable Pin Change Interrupt for next character #else out PCMSK0,SERIAL_PORT ; enable Pin Change Interrupt for next character #endif #endif #ifdef MCU_TYPE_ATMEGAX8 sts PCMSK2,SERIAL_PORT ; enable Pin Change Interrupt for next character #endif SERIAL_RECEIVE_RETI: out SREG,SERIAL_INTERRUPT_SREG reti #ifdef MCU_TYPE_ATMEGAX8 ; Pin Change Interrupt used to detect external I/O input V_PCINT0: #ifdef OPTION_REMOTE_IO_OR_CAR_SECURITY in SERIAL_INTERRUPT_SREG,SREG ; check for change in the input bits in SERIAL_SCRATCH,PINB ; get input byte push SCRATCH0 ; preserve scratch registers push SCRATCH1 lds SCRATCH0,IO_FLAG_BYTE sbrc SCRATCH0,REMOTE_IO_FLAG_BIT rjmp PCINT0_NO_IO ; if flag already set, do nothing ; ( previous-value EOR current-value ) AND ; ( ( current value AND alert on high mask ) OR ; ( ( NOT current value ) AND alert on low mask ) ) lds SCRATCH0,IO_ALERT_ON_HIGH_MASK and SCRATCH0,SERIAL_SCRATCH lds SCRATCH1,IO_ALERT_ON_LOW_MASK com SERIAL_SCRATCH and SCRATCH1,SERIAL_SCRATCH com SERIAL_SCRATCH or SCRATCH0,SCRATCH1 lds SCRATCH1,IO_PREVIOUS_VALUE eor SCRATCH1,SERIAL_SCRATCH and SCRATCH0,SCRATCH1 ; if zero flag false, send alert breq PCINT0_NO_SET_IO_FLAG ldi SCRATCH0,1< 45123) ; or 0xff if you want to terminate on decimal point ; If decimal . found and DELIM set to '.' parse one fractional digit, so "45.67" becomes 456 ; SCRATCH0123 and CHAR used PARSE_DECIMAL: clt ; T flag marks last digit after '.' clr SCRATCH0 clr SCRATCH1 PSD_LOOP: ; Get digit ld CHAR,X+ tst DELIM brne PSD_NOT_SKIP_DECIMAL cpi CHAR,'.' ; skip decimal mode breq PSD_NEXTCHAR PSD_NOT_SKIP_DECIMAL: cp CHAR,DELIM brne PSD_NOT_DECIMAL set rjmp PSD_NEXTCHAR PSD_NOT_DECIMAL: subi CHAR,'0' brlo PSD_DONE cpi CHAR,10 brsh PSD_DONE ; multiply by 10 rcall MULX10_SCRATCH10 ; add digit clr SCRATCH2 add SCRATCH0,CHAR adc SCRATCH1,SCRATCH2 ; brts PSD_DONE ; out if decimal and one more digit PSD_NEXTCHAR: dec PAT brne PSD_LOOP PSD_DONE: ret ; multiply by 10 ( X*10 = X*2 + X*8 ) MULX10_SCRATCH10: lsl SCRATCH0 rol SCRATCH1 mov SCRATCH3,SCRATCH0 mov SCRATCH2,SCRATCH1 lsl SCRATCH3 rol SCRATCH2 lsl SCRATCH3 rol SCRATCH2 add SCRATCH0,SCRATCH3 adc SCRATCH1,SCRATCH2 ret ; Called to parse and execute SETNAME command ; Expected: one parameter ; Saves device name to EEPROM ; Called while serial comm is running CMD_SETNAME: rcall CLEAR_PARSE_FIELDS ldi ZH,high(SETNAME_PARSE_STRING<<1) ldi ZL,low(SETNAME_PARSE_STRING<<1) cbr FLAG_REGISTER,1<= 30000, assume it is a rollover and take 60,000 - result ldi SCRATCH1,high(30000) ldi SCRATCH0,low(30000) ; no cpci cp SCRATCH2,SCRATCH0 cpc SCRATCH3,SCRATCH1 brlo CPD_NOT_ROLLOVER mov SCRATCH0,SCRATCH2 mov SCRATCH1,SCRATCH3 ldi SCRATCH3,high(60000) ldi SCRATCH2,low(60000) sub SCRATCH2,SCRATCH0 sbc SCRATCH3,SCRATCH1 CPD_NOT_ROLLOVER: ; Get minimum displacement in SCRATCH1:SCRATCH0 ldi XH,high(EEADR_TRACK_MIN_DISPLACEMENT) ldi XL,low(EEADR_TRACK_MIN_DISPLACEMENT) rcall EEPROM_READWORD_X_TO_SCRATCH10 ; Compare with calculated displacement cp SCRATCH2,SCRATCH0 cpc SCRATCH3,SCRATCH1 ; Here carry is SET if we have NOT moved ret #ifdef ALT_IN_FEET #define NEED_UNITS_CONVERT 1 #endif #ifdef SPEED_IN_MPH #define NEED_UNITS_CONVERT 1 #endif #ifdef SPEED_IN_KPH #define NEED_UNITS_CONVERT 1 #endif #ifdef NEED_UNITS_CONVERT ; Units conversion ; Call with number in SCRATCH1:SCRATCH0 (from PARSE_DECIMAL) ; Conversion factor in XH:XL ; Result returned in ZH:ZL ; Does a 16x16 bit multiply, retaining only the high order word of the product ; This took quite a while to figure out! The trick is to move carry into MSB. UNITS_CONVERT_X4: lsl SCRATCH0 rol SCRATCH1 UNITS_CONVERT_X2: lsl SCRATCH0 rol SCRATCH1 UNITS_CONVERT: ldi SCRATCH2,16 clr ZH clr ZL UC_LOOP: lsr XH ror XL brcc UC_ZERO add ZL,SCRATCH0 adc ZH,SCRATCH1 UC_ZERO: ror ZH ; carry from previous addition becomes MSB ror ZL dec SCRATCH2 brne UC_LOOP ret #endif ; Locate and send, called from CMD_LOCATE via scheduled command GPS_LOCATE_AND_SEND: rcall GPS_LOCATE ldi SCRATCH0,FIX_TYPE_LOCATE - FIX_TYPE_BASE sts SEND_STRING_OFFSET_1,SCRATCH0 ; GPS_SEND_LOCATION called by tracking function, assumes we have a locate in memory GPS_SEND_LOCATION: lds SCRATCH1,GPS_STATUS ldi SCRATCH0,PHONE_STRING_GPS_DATASTREAM_TIMEOUT - PHONE_STRING_BASE cpi SCRATCH1,GPS_STATUS_DATASTREAM_TIMEOUT breq MULTI_SEND_DO_1 ldi SCRATCH0,PHONE_STRING_GPS_FIX_TIMEOUT - PHONE_STRING_BASE cpi SCRATCH1,GPS_STATUS_FIX_TIMEOUT breq MULTI_SEND_DO_1 ldi SCRATCH0,PHONE_STRING_GPS_LOCATION - PHONE_STRING_BASE #ifdef OPTION_REMOTE_IO_OR_CAR_SECURITY MULTI_SEND_DO_1: #endif rjmp MULTI_SEND_DO ; Send a variety of messages depending on entry point ; Called from COMMAND_PENDING MULTI_SEND_COMMAND_EXECUTED: ldi SCRATCH0,PHONE_STRING_COMMAND_EXECUTED - PHONE_STRING_BASE rjmp MULTI_SEND_DO MULTI_SEND_PASSWORD_CHANGED: ldi SCRATCH0,PHONE_STRING_PASSWORD_CHANGED - PHONE_STRING_BASE rjmp MULTI_SEND_DO MULTI_SEND_PASSWORD_CHANGE_FAILED: ldi SCRATCH0,PHONE_STRING_PASSWORD_CHANGE_FAILED - PHONE_STRING_BASE rjmp MULTI_SEND_DO #ifdef OPTION_REMOTE_IO_OR_CAR_SECURITY MULTI_SEND_ALERT: #ifdef OPTION_CAR_SECURITY rcall GPS_LOCATE lds SCRATCH1,IO_PREVIOUS_VALUE ; saved by interrupt ldi SCRATCH0,FIX_TYPE_ALARM_POWER - FIX_TYPE_BASE sbrs SCRATCH1,ALARM_TRIGGER2_IN ldi SCRATCH0,FIX_TYPE_ALARM2 - FIX_TYPE_BASE sbrs SCRATCH1,ALARM_TRIGGER1_IN ldi SCRATCH0,FIX_TYPE_ALARM1 - FIX_TYPE_BASE sts SEND_STRING_OFFSET_1,SCRATCH0 rcall GPS_SEND_LOCATION #else ; OPTION_REMOTE_IO ldi SCRATCH0,INPUT_TYPE_ALERT - INPUT_TYPE_BASE sts SEND_STRING_OFFSET_1,SCRATCH0 ldi XH,high(PARSE_FIELDS) ; address of first ldi XL,low(PARSE_FIELDS) ; output byte lds SCRATCH0,IO_PREVIOUS_VALUE rcall MULTI_SEND_INPUT_ALERT #endif ; OPTION_REMOTE_IO #ifdef MCU_TYPE_ATTINY84 in SCRATCH0,PIN_SERIAL #endif #ifdef MCU_TYPE_ATMEGAX8 in SCRATCH0,PINB #endif ; so a series of changes don't cause multiple messages, sts IO_PREVIOUS_VALUE,SCRATCH0 ; save value AFTER sending message sts IO_FLAG_BYTE,REG_ZERO ret #endif ; OPTION_REMOTE_IO_OR_CAR_SECURITY #ifdef OPTION_REMOTE_IO MULTI_SEND_INPUT: ldi SCRATCH0,INPUT_TYPE_INPUT - INPUT_TYPE_BASE sts SEND_STRING_OFFSET_1,SCRATCH0 ldi XH,high(PARSE_FIELDS) ; address of first ldi XL,low(PARSE_FIELDS) ; output byte #ifdef OPTION_REMOTE_IO_TEXT ; Remote IO TEXT #ifdef MCU_TYPE_ATTINY84 in SCRATCH0,PIN_SERIAL #endif #ifdef MCU_TYPE_ATMEGAX8 in SCRATCH0,PINB #endif MULTI_SEND_INPUT_ALERT: push ZH push ZL ldi ZH,high(PHONE_STRING_INPUT_TEXT<<1) ldi ZL,low(PHONE_STRING_INPUT_TEXT<<1) MSIT_LOOP: ; Copy it into RAM and replace ! with the bits lpm SCRATCH1,Z+ cpi SCRATCH1,'!' brne MSIT_NOTVAR ; not a variable ! field ldi SCRATCH1,'-' ; for high (inactive) sbrs SCRATCH0,7 ; test high bit ldi SCRATCH1,'+' ; for low (active) lsl SCRATCH0 MSIT_NOTVAR: st X+,SCRATCH1 tst SCRATCH1 brne MSIT_LOOP ; pop ZL pop ZH ldi SCRATCH0,PHONE_STRING_INPUT - PHONE_STRING_BASE rjmp MULTI_SEND_DO ; End Remote IO TEXT #else // Not REMOTE_IO_TEXT #ifdef MCU_TYPE_ATTINY84 in SCRATCH0,PIN_SERIAL #endif #ifdef MCU_TYPE_ATMEGAX8 in SCRATCH0,PINB #endif MULTI_SEND_INPUT_ALERT: rcall MULTI_SEND_INPUT_COMMON_1 #ifdef MCU_TYPE_ATTINY84 in SCRATCH0,DDR_SERIAL #endif #ifdef MCU_TYPE_ATMEGAX8 in SCRATCH0,DDRB #endif rcall MULTI_SEND_INPUT_COMMON_1 lds SCRATCH0,IO_ALERT_ON_LOW_MASK rcall MULTI_SEND_INPUT_COMMON_1 lds SCRATCH0,IO_ALERT_ON_HIGH_MASK rcall MULTI_SEND_INPUT_COMMON_1 ldi SCRATCH0,PHONE_STRING_INPUT - PHONE_STRING_BASE rjmp MULTI_SEND_DO MULTI_SEND_INPUT_COMMON_1: #ifdef MCU_TYPE_ATTINY84 lsr SCRATCH0 lsr SCRATCH0 lsr SCRATCH0 #endif st X+,REG_ZERO ; high byte st X+,SCRATCH0 ret #endif // REMOTE_IO_TEXT ; IFDEFs in MEASURE raged out of control, so just write two different functions MULTI_SEND_MEASURE: #ifdef MCU_TYPE_ATTINY84 ldi SCRATCH0,(1< ",0, \ low(PHONE_GOT_BATTERY_CHARGE),high(PHONE_GOT_BATTERY_CHARGE),"+CBC: 0,",0, \ low(PHONE_GOT_BATTERY_CHARGE),high(PHONE_GOT_BATTERY_CHARGE),"+CBC: 1,",0, \ low(PHONE_GOT_SIGNAL_STRENGTH),high(PHONE_GOT_SIGNAL_STRENGTH),"+CSQ: ",0, \ low(PHONE_INIT_ERROR),high(PHONE_INIT_ERROR),0 ; These functions should not mess up the Y pointer. #ifdef OPTION_REMOTE_IO COMMAND_MATCH_PATTERN: .db low(CMD_SETADDRESS),high(CMD_SETADDRESS),"SETADDRESS",0, \ low(CMD_SETNAME),high(CMD_SETNAME),"SETNAME",0, \ low(CMD_SETPASSWORD),high(CMD_SETPASSWORD),"SETPASSWORD",0, \ low(CMD_SETTRACK),high(CMD_SETTRACK),"SETTRACK",0, \ low(CMD_SETPOWER),high(CMD_SETPOWER),"SETPOWER",0, \ low(CMD_SETSPEED),high(CMD_SETSPEED),"SETSPEED",0, \ low(CMD_STATUS),high(CMD_STATUS),"STATUS",0, \ low(CMD_LOCATE),high(CMD_LOCATE),"LOCATE",0, \ low(CMD_SALOCATE),high(CMD_SALOCATE),"SALOCATE",0, \ low(CMD_TRACKOFF),high(CMD_TRACKOFF),"TRACKOFF",0, \ low(CMD_TRACKON),high(CMD_TRACKON),"TRACKON",0, \ low(CMD_POWERSAVE),high(CMD_POWERSAVE),"POWERSAVE",0, \ low(CMD_POWERON),high(CMD_POWERON),"POWERON",0, \ low(CMD_OUTPUT),high(CMD_OUTPUT),"OUTPUT",0, \ low(CMD_OUTPULSE),high(CMD_OUTPULSE),"OUTPULSE",0, \ low(CMD_INPUT),high(CMD_INPUT),"INPUT",0, \ low(CMD_ALERT),high(CMD_ALERT),"ALERT",0, \ low(CMD_SETIO),high(CMD_SETIO),"SETIO",0, \ low(CMD_MEASURE),high(CMD_MEASURE),"MEASURE",0, \ low(CMD_REBOOT),high(CMD_REBOOT),"REBOOT",0, \ low(CMD_REINIT),high(CMD_REINIT),"REINIT",0, \ low(CMD_CAUSEWDR),high(CMD_CAUSEWDR),"CAUSEWDR",0, \ low(CMD_UNRECOGNIZED),high(CMD_UNRECOGNIZED),0 #else #ifdef OPTION_CAR_SECURITY COMMAND_MATCH_PATTERN: .db low(CMD_SETADDRESS),high(CMD_SETADDRESS),"SETADDRESS",0, \ low(CMD_SETNAME),high(CMD_SETNAME),"SETNAME",0, \ low(CMD_SETPASSWORD),high(CMD_SETPASSWORD),"SETPASSWORD",0, \ low(CMD_SETTRACK),high(CMD_SETTRACK),"SETTRACK",0, \ low(CMD_SETPOWER),high(CMD_SETPOWER),"SETPOWER",0, \ low(CMD_SETSPEED),high(CMD_SETSPEED),"SETSPEED",0, \ low(CMD_STATUS),high(CMD_STATUS),"STATUS",0, \ low(CMD_LOCATE),high(CMD_LOCATE),"LOCATE",0, \ low(CMD_SALOCATE),high(CMD_SALOCATE),"SALOCATE",0, \ low(CMD_TRACKOFF),high(CMD_TRACKOFF),"TRACKOFF",0, \ low(CMD_TRACKON),high(CMD_TRACKON),"TRACKON",0, \ low(CMD_POWERSAVE),high(CMD_POWERSAVE),"POWERSAVE",0, \ low(CMD_POWERON),high(CMD_POWERON),"POWERON",0, \ low(CMD_REBOOT),high(CMD_REBOOT),"REBOOT",0, \ low(CMD_REINIT),high(CMD_REINIT),"REINIT",0, \ low(CMD_CAUSEWDR),high(CMD_CAUSEWDR),"CAUSEWDR",0, \ low(CMD_CARDISABLE),high(CMD_CARDISABLE),"CARDISABLE",0, \ low(CMD_CARENABLE),high(CMD_CARENABLE),"CARENABLE",0, \ low(CMD_HONK),high(CMD_HONK),"HONK",0, \ low(CMD_CARUNLOCK),high(CMD_CARUNLOCK),"CARUNLOCK",0, \ low(CMD_UNRECOGNIZED),high(CMD_UNRECOGNIZED),0 #else COMMAND_MATCH_PATTERN: .db low(CMD_SETADDRESS),high(CMD_SETADDRESS),"SETADDRESS",0, \ low(CMD_SETNAME),high(CMD_SETNAME),"SETNAME",0, \ low(CMD_SETPASSWORD),high(CMD_SETPASSWORD),"SETPASSWORD",0, \ low(CMD_SETTRACK),high(CMD_SETTRACK),"SETTRACK",0, \ low(CMD_SETPOWER),high(CMD_SETPOWER),"SETPOWER",0, \ low(CMD_SETSPEED),high(CMD_SETSPEED),"SETSPEED",0, \ low(CMD_STATUS),high(CMD_STATUS),"STATUS",0, \ low(CMD_LOCATE),high(CMD_LOCATE),"LOCATE",0, \ low(CMD_SALOCATE),high(CMD_SALOCATE),"SALOCATE",0, \ low(CMD_TRACKOFF),high(CMD_TRACKOFF),"TRACKOFF",0, \ low(CMD_TRACKON),high(CMD_TRACKON),"TRACKON",0, \ low(CMD_POWERSAVE),high(CMD_POWERSAVE),"POWERSAVE",0, \ low(CMD_POWERON),high(CMD_POWERON),"POWERON",0, \ low(CMD_REBOOT),high(CMD_REBOOT),"REBOOT",0, \ low(CMD_REINIT),high(CMD_REINIT),"REINIT",0, \ low(CMD_CAUSEWDR),high(CMD_CAUSEWDR),"CAUSEWDR",0, \ low(CMD_UNRECOGNIZED),high(CMD_UNRECOGNIZED),0 #endif #endif CMGL_MATCH_PATTERN: .db low(PPMN_CSMS_MATCH),high(PPMN_CSMS_MATCH),",",0, \ low(PPMN_CSMS_MATCH),high(PPMN_CSMS_MATCH),34,0, \ low(PPMN_CSMS_SENT),high(PPMN_CSMS_SENT),"STO SENT",0, \ low(PPMN_CSMS_UNSENT),high(PPMN_CSMS_UNSENT),"STO UNSENT",0, \ low(PPMN_CSMS_RECEIVED),high(PPMN_CSMS_RECEIVED),"REC ",0, \ low(PPMN_OUT),high(PPMN_OUT),0 ; SETNAME_PARSE_STRING: .db 1,(FLDLEN_DEVICENAME<<2)+high(FLDADR_DEVICENAME),low(FLDADR_DEVICENAME), \ 0xff SETPASSWORD_PARSE_STRING: .db 1,(FLDLEN_PASSWORD1<<2)+high(FLDADR_PASSWORD1),low(FLDADR_PASSWORD1), \ 2,(FLDLEN_PASSWORD2<<2)+high(FLDADR_PASSWORD2),low(FLDADR_PASSWORD2), \ 0xff #ifdef DEBUG_MESSAGE_COUNT_ENABLE PHONE_SEND_STORE_MESSAGE_STRING: .db 0xf0,INIT_RECEIVE_TIMEOUT,"ATE0",13,0, \ 0xf0,DEFAULT_RECEIVE_TIMEOUT, \ "AT+CMGW=",34,0xfe, \ high(EEADR_PHONE_NUMBER)+(EELEN_PHONE_NUMBER<<2), \ low(EEADR_PHONE_NUMBER),34,13,0, \ 0xf7,0xff,high(EEADR_EMAIL_ADDR)+(EELEN_EMAIL_ADDR<<2), \ low(EEADR_EMAIL_ADDR), \ 0xff,high(EEADR_DEVICENAME)+(EELEN_DEVICENAME<<2), \ low(EEADR_DEVICENAME), \ "MC=",0xf8,high(DEBUG_MESSAGE_COUNT),low(DEBUG_MESSAGE_COUNT)," ", \ 0xfa,high(PHONE_STRING_BASE<<1),low(PHONE_STRING_BASE<<1),0xf7,26,13,0,0 #else PHONE_SEND_STORE_MESSAGE_STRING: .db 0xf0,INIT_RECEIVE_TIMEOUT,"ATE0",13,0, \ 0xf0,DEFAULT_RECEIVE_TIMEOUT, \ "AT+CMGW=",34,0xfe, \ high(EEADR_PHONE_NUMBER)+(EELEN_PHONE_NUMBER<<2), \ low(EEADR_PHONE_NUMBER),34,13,0, \ 0xf7,0xff,high(EEADR_EMAIL_ADDR)+(EELEN_EMAIL_ADDR<<2), \ low(EEADR_EMAIL_ADDR), \ 0xff,high(EEADR_DEVICENAME)+(EELEN_DEVICENAME<<2), \ low(EEADR_DEVICENAME), \ 0xfa,high(PHONE_STRING_BASE<<1),low(PHONE_STRING_BASE<<1),0xf7,26,13,0,0 #endif #ifdef PHONE_TYPE_WMOD2 PHONE_SEND_TRANSMIT_MESSAGE_STRING: .db 0xf0,INIT_RECEIVE_TIMEOUT,"ATE0",13,0,0xf0,SMS_SEND_RECEIVE_TIMEOUT, \ "AT+CMSS=",0xfd,(4<<2)+high(CURRENT_SMS),low(CURRENT_SMS),13,0, \ "AT+CMGD=",0xfd,(4<<2)+high(CURRENT_SMS),low(CURRENT_SMS),13,0,0 #else PHONE_SEND_TRANSMIT_MESSAGE_STRING: .db 0xf0,INIT_RECEIVE_TIMEOUT,"ATE0",13,0,0xf0,SMS_SEND_RECEIVE_TIMEOUT, \ "AT+CMSS=",0xfd,(4<<2)+high(CURRENT_SMS),low(CURRENT_SMS),13,0,0 #endif ; Phone string offsets from one base can be up to 512 bytes due to word addressing PHONE_STRING_BASE: PHONE_STRING_COMMAND_EXECUTED: .db "COMMAND EXECUTED",0 PHONE_STRING_PASSWORD_CHANGED: .db "PASSWORD CHANGED",0 PHONE_STRING_PASSWORD_CHANGE_FAILED: .db "PASSWORD CHANGE FAILED",0 PHONE_STRING_UNKNOWN_COMMAND: .db "UNKNOWN COMMAND",0 #ifdef OPTION_CAR_SECURITY PHONE_STRING_GPS_DATASTREAM_TIMEOUT: .db 0xfb,high(FIX_TYPE_BASE<<1),low(FIX_TYPE_BASE<<1), \ " NO DATASTREAM FROM GPS DEVICE", \ 0xfc,high(LAST_GOOD_FIX_STRING<<1),low(LAST_GOOD_FIX_STRING<<1),0 PHONE_STRING_GPS_FIX_TIMEOUT: .db 0xfb,high(FIX_TYPE_BASE<<1),low(FIX_TYPE_BASE<<1), \ " GPS TIMED OUT WAITING FOR FIX", \ 0xfc,high(LAST_GOOD_FIX_STRING<<1),low(LAST_GOOD_FIX_STRING<<1),0 #else PHONE_STRING_GPS_DATASTREAM_TIMEOUT: .db "NO DATASTREAM FROM GPS DEVICE", \ 0xfc,high(LAST_GOOD_FIX_STRING<<1),low(LAST_GOOD_FIX_STRING<<1),0 PHONE_STRING_GPS_FIX_TIMEOUT: .db "GPS TIMED OUT WAITING FOR FIX", \ 0xfc,high(LAST_GOOD_FIX_STRING<<1),low(LAST_GOOD_FIX_STRING<<1),0 #endif #ifdef OPTION_REMOTE_IO #ifdef OPTION_REMOTE_IO_TEXT PHONE_STRING_INPUT: .db 0xfb,high(INPUT_TYPE_BASE<<1),low(INPUT_TYPE_BASE<<1)," ", \ 0xfd,(32<<2)+high(PARSE_FIELDS),low(PARSE_FIELDS), \ 0xfd,(32<<2)+high(PARSE_FIELDS+32),low(PARSE_FIELDS+32), \ 0 ; 0xfd,(32<<2)+high(PARSE_FIELDS+64),low(PARSE_FIELDS+64), \ ; Put your strings here for text mode, move in and decomment line above if over 64 characters ; Over 64 characters only allowed for ATMEGA88, and 64 includes the null. ; Note the ! are replaced by + or - ; and for ATTINY84 they start at bit 7 and go to 3 (five of them). ; For ATMEGA88 there are 8 in order from B7 to B0. ; Fewer than eight ! marks reads from B7 onward. PHONE_STRING_INPUT_TEXT: .db "COND1! COND2! COND3! COND4! COND5! COND6! COND7! COND8!",0 #else PHONE_STRING_INPUT: .db 0xfb,high(INPUT_TYPE_BASE<<1),low(INPUT_TYPE_BASE<<1), \ " DATA ",0xf8,high(FLDADR_INPUT_BYTE1),low(FLDADR_INPUT_BYTE1), \ " DDR ",0xf8,high(FLDADR_INPUT_BYTE2),low(FLDADR_INPUT_BYTE2)," ALERTMASK LOW ", \ 0xf8,high(FLDADR_INPUT_BYTE3),low(FLDADR_INPUT_BYTE3)," HIGH ", \ 0xf8,high(FLDADR_INPUT_BYTE4),low(FLDADR_INPUT_BYTE4),0 #endif PHONE_STRING_MEASURE: .db "MEASURE ", \ 0xf8,high(PARSE_FIELDS + 0),low(PARSE_FIELDS + 0)," ", \ 0xf8,high(PARSE_FIELDS + 2),low(PARSE_FIELDS + 2)," ", \ 0xf8,high(PARSE_FIELDS + 4),low(PARSE_FIELDS + 4)," ", \ 0xf8,high(PARSE_FIELDS + 6),low(PARSE_FIELDS + 6)," ", \ 0xf8,high(PARSE_FIELDS + 8),low(PARSE_FIELDS + 8)," ", \ 0xf8,high(PARSE_FIELDS + 10),low(PARSE_FIELDS + 10),0 INPUT_TYPE_BASE: INPUT_TYPE_INPUT: .db "INPUT",0 INPUT_TYPE_ALERT: .db "ALERT",0 #endif ; There are three different speed units, and two different altitude units options. ; The assembler will add a null byte after a string if there is an odd number of bytes. ; As far as I know there is no way to incorporate an externally defined string into ; a .db structure. That means I have to define all six cases here, instead of having ; ifdefs inside the string. :-( #ifdef SPEED_IN_MPH #ifdef ALT_IN_FEET PHONE_STRING_GPS_LOCATION: .db 0xfb,high(FIX_TYPE_BASE<<1),low(FIX_TYPE_BASE<<1), \ " POS ",0xfd,(2<<2)+high(FLDADR_GPRMC_LATITUDE),low(FLDADR_GPRMC_LATITUDE)," ", \ 0xfd,((FLDLEN_GPRMC_LATITUDE-2)<<2)+high(FLDADR_GPRMC_LATITUDE+2),low(FLDADR_GPRMC_LATITUDE+2), \ " ",0xfd,(FLDLEN_GPRMC_LATDIR<<2)+high(FLDADR_GPRMC_LATDIR),low(FLDADR_GPRMC_LATDIR), \ " ",0xfd,(3<<2)+high(FLDADR_GPRMC_LONGITUDE),low(FLDADR_GPRMC_LONGITUDE), \ " ",0xfd,((FLDLEN_GPRMC_LONGITUDE-3)<<2)+high(FLDADR_GPRMC_LONGITUDE+3),low(FLDADR_GPRMC_LONGITUDE+3), \ " ",0xfd,(FLDLEN_GPRMC_LONGDIR<<2)+high(FLDADR_GPRMC_LONGDIR),low(FLDADR_GPRMC_LONGDIR), \ " ALT ",0xf8,high(FLDADR_GPGGA_ALT_NUMERIC),low(FLDADR_GPGGA_ALT_NUMERIC)," FT", \ " SPEED ",0xf9,high(FLDADR_GPRMC_SPEED_NUMERIC),low(FLDADR_GPRMC_SPEED_NUMERIC)," MPH", \ " COURSE ",0xfd,(FLDLEN_GPRMC_COURSE<<2)+high(FLDADR_GPRMC_COURSE),low(FLDADR_GPRMC_COURSE), \ " AT ",0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+4),low(FLDADR_GPRMC_DATE+4),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+2),low(FLDADR_GPRMC_DATE+2),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE),low(FLDADR_GPRMC_DATE)," ", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME),low(FLDADR_GPRMC_TIME),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+2),low(FLDADR_GPRMC_TIME+2),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+4),low(FLDADR_GPRMC_TIME+4)," UTC", \ " SATS ",0xfd,(FLDLEN_GPGGA_SATS<<2)+high(FLDADR_GPGGA_SATS),low(FLDADR_GPGGA_SATS),0 #endif #endif #ifdef SPEED_IN_KPH #ifdef ALT_IN_FEET PHONE_STRING_GPS_LOCATION: .db 0xfb,high(FIX_TYPE_BASE<<1),low(FIX_TYPE_BASE<<1), \ " POS ",0xfd,(2<<2)+high(FLDADR_GPRMC_LATITUDE),low(FLDADR_GPRMC_LATITUDE)," ", \ 0xfd,((FLDLEN_GPRMC_LATITUDE-2)<<2)+high(FLDADR_GPRMC_LATITUDE+2),low(FLDADR_GPRMC_LATITUDE+2), \ " ",0xfd,(FLDLEN_GPRMC_LATDIR<<2)+high(FLDADR_GPRMC_LATDIR),low(FLDADR_GPRMC_LATDIR), \ " ",0xfd,(3<<2)+high(FLDADR_GPRMC_LONGITUDE),low(FLDADR_GPRMC_LONGITUDE), \ " ",0xfd,((FLDLEN_GPRMC_LONGITUDE-3)<<2)+high(FLDADR_GPRMC_LONGITUDE+3),low(FLDADR_GPRMC_LONGITUDE+3), \ " ",0xfd,(FLDLEN_GPRMC_LONGDIR<<2)+high(FLDADR_GPRMC_LONGDIR),low(FLDADR_GPRMC_LONGDIR), \ " ALT ",0xf8,high(FLDADR_GPGGA_ALT_NUMERIC),low(FLDADR_GPGGA_ALT_NUMERIC)," FT", \ " SPEED ",0xf9,high(FLDADR_GPRMC_SPEED_NUMERIC),low(FLDADR_GPRMC_SPEED_NUMERIC)," KPH", \ " COURSE ",0xfd,(FLDLEN_GPRMC_COURSE<<2)+high(FLDADR_GPRMC_COURSE),low(FLDADR_GPRMC_COURSE), \ " AT ",0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+4),low(FLDADR_GPRMC_DATE+4),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+2),low(FLDADR_GPRMC_DATE+2),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE),low(FLDADR_GPRMC_DATE)," ", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME),low(FLDADR_GPRMC_TIME),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+2),low(FLDADR_GPRMC_TIME+2),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+4),low(FLDADR_GPRMC_TIME+4)," UTC", \ " SATS ",0xfd,(FLDLEN_GPGGA_SATS<<2)+high(FLDADR_GPGGA_SATS),low(FLDADR_GPGGA_SATS),0 #endif #endif #ifdef SPEED_IN_KNOTS #ifdef ALT_IN_FEET PHONE_STRING_GPS_LOCATION: .db 0xfb,high(FIX_TYPE_BASE<<1),low(FIX_TYPE_BASE<<1), \ " POS ",0xfd,(2<<2)+high(FLDADR_GPRMC_LATITUDE),low(FLDADR_GPRMC_LATITUDE)," ", \ 0xfd,((FLDLEN_GPRMC_LATITUDE-2)<<2)+high(FLDADR_GPRMC_LATITUDE+2),low(FLDADR_GPRMC_LATITUDE+2), \ " ",0xfd,(FLDLEN_GPRMC_LATDIR<<2)+high(FLDADR_GPRMC_LATDIR),low(FLDADR_GPRMC_LATDIR), \ " ",0xfd,(3<<2)+high(FLDADR_GPRMC_LONGITUDE),low(FLDADR_GPRMC_LONGITUDE), \ " ",0xfd,((FLDLEN_GPRMC_LONGITUDE-3)<<2)+high(FLDADR_GPRMC_LONGITUDE+3),low(FLDADR_GPRMC_LONGITUDE+3), \ " ",0xfd,(FLDLEN_GPRMC_LONGDIR<<2)+high(FLDADR_GPRMC_LONGDIR),low(FLDADR_GPRMC_LONGDIR), \ " ALT ",0xf8,high(FLDADR_GPGGA_ALT_NUMERIC),low(FLDADR_GPGGA_ALT_NUMERIC)," FT", \ " SPEED ",0xf9,high(FLDADR_GPRMC_SPEED_NUMERIC),low(FLDADR_GPRMC_SPEED_NUMERIC)," KNOTS", \ " COURSE ",0xfd,(FLDLEN_GPRMC_COURSE<<2)+high(FLDADR_GPRMC_COURSE),low(FLDADR_GPRMC_COURSE), \ " AT ",0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+4),low(FLDADR_GPRMC_DATE+4),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+2),low(FLDADR_GPRMC_DATE+2),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE),low(FLDADR_GPRMC_DATE)," ", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME),low(FLDADR_GPRMC_TIME),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+2),low(FLDADR_GPRMC_TIME+2),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+4),low(FLDADR_GPRMC_TIME+4)," UTC", \ " SATS ",0xfd,(FLDLEN_GPGGA_SATS<<2)+high(FLDADR_GPGGA_SATS),low(FLDADR_GPGGA_SATS),0 #endif #endif #ifdef SPEED_IN_MPH #ifdef ALT_IN_METERS PHONE_STRING_GPS_LOCATION: .db 0xfb,high(FIX_TYPE_BASE<<1),low(FIX_TYPE_BASE<<1), \ " POS ",0xfd,(2<<2)+high(FLDADR_GPRMC_LATITUDE),low(FLDADR_GPRMC_LATITUDE)," ", \ 0xfd,((FLDLEN_GPRMC_LATITUDE-2)<<2)+high(FLDADR_GPRMC_LATITUDE+2),low(FLDADR_GPRMC_LATITUDE+2), \ " ",0xfd,(FLDLEN_GPRMC_LATDIR<<2)+high(FLDADR_GPRMC_LATDIR),low(FLDADR_GPRMC_LATDIR), \ " ",0xfd,(3<<2)+high(FLDADR_GPRMC_LONGITUDE),low(FLDADR_GPRMC_LONGITUDE), \ " ",0xfd,((FLDLEN_GPRMC_LONGITUDE-3)<<2)+high(FLDADR_GPRMC_LONGITUDE+3),low(FLDADR_GPRMC_LONGITUDE+3), \ " ",0xfd,(FLDLEN_GPRMC_LONGDIR<<2)+high(FLDADR_GPRMC_LONGDIR),low(FLDADR_GPRMC_LONGDIR), \ " ALT ",0xf8,high(FLDADR_GPGGA_ALT_NUMERIC),low(FLDADR_GPGGA_ALT_NUMERIC)," M", \ " SPEED ",0xf9,high(FLDADR_GPRMC_SPEED_NUMERIC),low(FLDADR_GPRMC_SPEED_NUMERIC)," MPH", \ " COURSE ",0xfd,(FLDLEN_GPRMC_COURSE<<2)+high(FLDADR_GPRMC_COURSE),low(FLDADR_GPRMC_COURSE), \ " AT ",0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+4),low(FLDADR_GPRMC_DATE+4),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+2),low(FLDADR_GPRMC_DATE+2),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE),low(FLDADR_GPRMC_DATE)," ", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME),low(FLDADR_GPRMC_TIME),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+2),low(FLDADR_GPRMC_TIME+2),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+4),low(FLDADR_GPRMC_TIME+4)," UTC", \ " SATS ",0xfd,(FLDLEN_GPGGA_SATS<<2)+high(FLDADR_GPGGA_SATS),low(FLDADR_GPGGA_SATS),0 #endif #endif #ifdef SPEED_IN_KPH #ifdef ALT_IN_METERS PHONE_STRING_GPS_LOCATION: .db 0xfb,high(FIX_TYPE_BASE<<1),low(FIX_TYPE_BASE<<1), \ " POS ",0xfd,(2<<2)+high(FLDADR_GPRMC_LATITUDE),low(FLDADR_GPRMC_LATITUDE)," ", \ 0xfd,((FLDLEN_GPRMC_LATITUDE-2)<<2)+high(FLDADR_GPRMC_LATITUDE+2),low(FLDADR_GPRMC_LATITUDE+2), \ " ",0xfd,(FLDLEN_GPRMC_LATDIR<<2)+high(FLDADR_GPRMC_LATDIR),low(FLDADR_GPRMC_LATDIR), \ " ",0xfd,(3<<2)+high(FLDADR_GPRMC_LONGITUDE),low(FLDADR_GPRMC_LONGITUDE), \ " ",0xfd,((FLDLEN_GPRMC_LONGITUDE-3)<<2)+high(FLDADR_GPRMC_LONGITUDE+3),low(FLDADR_GPRMC_LONGITUDE+3), \ " ",0xfd,(FLDLEN_GPRMC_LONGDIR<<2)+high(FLDADR_GPRMC_LONGDIR),low(FLDADR_GPRMC_LONGDIR), \ " ALT ",0xf8,high(FLDADR_GPGGA_ALT_NUMERIC),low(FLDADR_GPGGA_ALT_NUMERIC)," M", \ " SPEED ",0xf9,high(FLDADR_GPRMC_SPEED_NUMERIC),low(FLDADR_GPRMC_SPEED_NUMERIC)," KPH", \ " COURSE ",0xfd,(FLDLEN_GPRMC_COURSE<<2)+high(FLDADR_GPRMC_COURSE),low(FLDADR_GPRMC_COURSE), \ " AT ",0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+4),low(FLDADR_GPRMC_DATE+4),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+2),low(FLDADR_GPRMC_DATE+2),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE),low(FLDADR_GPRMC_DATE)," ", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME),low(FLDADR_GPRMC_TIME),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+2),low(FLDADR_GPRMC_TIME+2),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+4),low(FLDADR_GPRMC_TIME+4)," UTC", \ " SATS ",0xfd,(FLDLEN_GPGGA_SATS<<2)+high(FLDADR_GPGGA_SATS),low(FLDADR_GPGGA_SATS),0 #endif #endif #ifdef SPEED_IN_KNOTS #ifdef ALT_IN_METERS PHONE_STRING_GPS_LOCATION: .db 0xfb,high(FIX_TYPE_BASE<<1),low(FIX_TYPE_BASE<<1), \ " POS ",0xfd,(2<<2)+high(FLDADR_GPRMC_LATITUDE),low(FLDADR_GPRMC_LATITUDE)," ", \ 0xfd,((FLDLEN_GPRMC_LATITUDE-2)<<2)+high(FLDADR_GPRMC_LATITUDE+2),low(FLDADR_GPRMC_LATITUDE+2), \ " ",0xfd,(FLDLEN_GPRMC_LATDIR<<2)+high(FLDADR_GPRMC_LATDIR),low(FLDADR_GPRMC_LATDIR), \ " ",0xfd,(3<<2)+high(FLDADR_GPRMC_LONGITUDE),low(FLDADR_GPRMC_LONGITUDE), \ " ",0xfd,((FLDLEN_GPRMC_LONGITUDE-3)<<2)+high(FLDADR_GPRMC_LONGITUDE+3),low(FLDADR_GPRMC_LONGITUDE+3), \ " ",0xfd,(FLDLEN_GPRMC_LONGDIR<<2)+high(FLDADR_GPRMC_LONGDIR),low(FLDADR_GPRMC_LONGDIR), \ " ALT ",0xf8,high(FLDADR_GPGGA_ALT_NUMERIC),low(FLDADR_GPGGA_ALT_NUMERIC)," M", \ " SPEED ",0xf9,high(FLDADR_GPRMC_SPEED_NUMERIC),low(FLDADR_GPRMC_SPEED_NUMERIC)," KNOTS", \ " COURSE ",0xfd,(FLDLEN_GPRMC_COURSE<<2)+high(FLDADR_GPRMC_COURSE),low(FLDADR_GPRMC_COURSE), \ " AT ",0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+4),low(FLDADR_GPRMC_DATE+4),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE+2),low(FLDADR_GPRMC_DATE+2),"/", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_DATE),low(FLDADR_GPRMC_DATE)," ", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME),low(FLDADR_GPRMC_TIME),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+2),low(FLDADR_GPRMC_TIME+2),":", \ 0xfd,(2<<2)+high(FLDADR_GPRMC_TIME+4),low(FLDADR_GPRMC_TIME+4)," UTC", \ " SATS ",0xfd,(FLDLEN_GPGGA_SATS<<2)+high(FLDADR_GPGGA_SATS),low(FLDADR_GPGGA_SATS),0 #endif #endif #ifdef MEASURE_TRACKER_BATTERY PHONE_STRING_STATUS_MESSAGE: .db "SPDLMT=", \ 0xf8,high(STATUSMSG_SPEED_LIMIT), \ low(STATUSMSG_SPEED_LIMIT), " STOPD=", \ 0xf8,high(STATUSMSG_TRACK_STOPPED_FIX_INTERVAL), \ low(STATUSMSG_TRACK_STOPPED_FIX_INTERVAL),"/", \ 0xf8,high(STATUSMSG_TRACK_STOPPED_NOTIFY_DELAY), \ low(STATUSMSG_TRACK_STOPPED_NOTIFY_DELAY)," BLKD=", \ 0xf8,high(STATUSMSG_TRACK_BLOCKED_FIX_INTERVAL), \ low(STATUSMSG_TRACK_BLOCKED_FIX_INTERVAL),"/", \ 0xf8,high(STATUSMSG_TRACK_BLOCKED_NOTIFY_DELAY), \ low(STATUSMSG_TRACK_BLOCKED_NOTIFY_DELAY)," MOVNG=", \ 0xf8,high(STATUSMSG_TRACK_MOVING_FIX_INTERVAL), \ low(STATUSMSG_TRACK_MOVING_FIX_INTERVAL),"/", \ 0xf8,high(STATUSMSG_TRACK_MOVING_NOTIFY_FREQ), \ low(STATUSMSG_TRACK_MOVING_NOTIFY_FREQ)," PSV=", \ 0xf8,high(STATUSMSG_POWERSAVE_PHONE_OFF_INTERVAL), \ low(STATUSMSG_POWERSAVE_PHONE_OFF_INTERVAL),"/", \ 0xf8,high(STATUSMSG_POWERSAVE_PHONE_ON_INTERVAL), \ low(STATUSMSG_POWERSAVE_PHONE_ON_INTERVAL)," 3D/FIX/BLKD=", \ 0xf8,high(STATUSMSG_GPS_FOUR_SAT_WAIT_TIME), \ low(STATUSMSG_GPS_FOUR_SAT_WAIT_TIME),"/", \ 0xf8,high(STATUSMSG_GPS_FIX_WAIT_TIME), \ low(STATUSMSG_GPS_FIX_WAIT_TIME),"/", \ 0xf8,high(STATUSMSG_BLOCKED_GPS_FIX_WAIT_TIME), \ low(STATUSMSG_BLOCKED_GPS_FIX_WAIT_TIME)," MD/MS=", \ 0xf8,high(STATUSMSG_MIN_DISPLACEMENT), \ low(STATUSMSG_MIN_DISPLACEMENT),"/", \ 0xf8,high(STATUSMSG_GPS_MOVING_THRESHOLD), \ low(STATUSMSG_GPS_MOVING_THRESHOLD),"/", \ 0xf8,high(STATUSMSG_GPS_MOVING_RETRY_THRESHOLD), \ low(STATUSMSG_GPS_MOVING_RETRY_THRESHOLD)," BAT=", \ 0xf8,high(STATUSMSG_BATTERY_CHARGE), \ low(STATUSMSG_BATTERY_CHARGE),"/", \ 0xf8,high(STATUSMSG_TRACKER_BATTERY_CHARGE), \ low(STATUSMSG_TRACKER_BATTERY_CHARGE)," SIG=", \ 0xf8,high(STATUSMSG_SIGNAL_STRENGTH), \ low(STATUSMSG_SIGNAL_STRENGTH)," WDR=", \ 0xf8,high(STATUSMSG_WDR_COUNT), \ low(STATUSMSG_WDR_COUNT)," V=0.19B Open GPS Tracker",0 #else PHONE_STRING_STATUS_MESSAGE: .db "SPDLMT=", \ 0xf8,high(STATUSMSG_SPEED_LIMIT), \ low(STATUSMSG_SPEED_LIMIT), " STOPD=", \ 0xf8,high(STATUSMSG_TRACK_STOPPED_FIX_INTERVAL), \ low(STATUSMSG_TRACK_STOPPED_FIX_INTERVAL),"/", \ 0xf8,high(STATUSMSG_TRACK_STOPPED_NOTIFY_DELAY), \ low(STATUSMSG_TRACK_STOPPED_NOTIFY_DELAY)," BLKD=", \ 0xf8,high(STATUSMSG_TRACK_BLOCKED_FIX_INTERVAL), \ low(STATUSMSG_TRACK_BLOCKED_FIX_INTERVAL),"/", \ 0xf8,high(STATUSMSG_TRACK_BLOCKED_NOTIFY_DELAY), \ low(STATUSMSG_TRACK_BLOCKED_NOTIFY_DELAY)," MOVNG=", \ 0xf8,high(STATUSMSG_TRACK_MOVING_FIX_INTERVAL), \ low(STATUSMSG_TRACK_MOVING_FIX_INTERVAL),"/", \ 0xf8,high(STATUSMSG_TRACK_MOVING_NOTIFY_FREQ), \ low(STATUSMSG_TRACK_MOVING_NOTIFY_FREQ)," PSV=", \ 0xf8,high(STATUSMSG_POWERSAVE_PHONE_OFF_INTERVAL), \ low(STATUSMSG_POWERSAVE_PHONE_OFF_INTERVAL),"/", \ 0xf8,high(STATUSMSG_POWERSAVE_PHONE_ON_INTERVAL), \ low(STATUSMSG_POWERSAVE_PHONE_ON_INTERVAL)," 3D/FIX/BLKD=", \ 0xf8,high(STATUSMSG_GPS_FOUR_SAT_WAIT_TIME), \ low(STATUSMSG_GPS_FOUR_SAT_WAIT_TIME),"/", \ 0xf8,high(STATUSMSG_GPS_FIX_WAIT_TIME), \ low(STATUSMSG_GPS_FIX_WAIT_TIME),"/", \ 0xf8,high(STATUSMSG_BLOCKED_GPS_FIX_WAIT_TIME), \ low(STATUSMSG_BLOCKED_GPS_FIX_WAIT_TIME)," MD/MS=", \ 0xf8,high(STATUSMSG_MIN_DISPLACEMENT), \ low(STATUSMSG_MIN_DISPLACEMENT),"/", \ 0xf8,high(STATUSMSG_GPS_MOVING_THRESHOLD), \ low(STATUSMSG_GPS_MOVING_THRESHOLD),"/", \ 0xf8,high(STATUSMSG_GPS_MOVING_RETRY_THRESHOLD), \ low(STATUSMSG_GPS_MOVING_RETRY_THRESHOLD)," BAT=", \ 0xf8,high(STATUSMSG_BATTERY_CHARGE), \ low(STATUSMSG_BATTERY_CHARGE)," SIG=", \ 0xf8,high(STATUSMSG_SIGNAL_STRENGTH), \ low(STATUSMSG_SIGNAL_STRENGTH)," WDR=", \ 0xf8,high(STATUSMSG_WDR_COUNT), \ low(STATUSMSG_WDR_COUNT)," V=0.19B Open GPS Tracker",0 #endif ;PHONE_STRING_WATCHDOG_RESET: ; .db "WATCHDOG RESET",0 FIX_TYPE_BASE: FIX_TYPE_STOPPED: .db "STOPPED",0 FIX_TYPE_STARTED: .db "STARTED",0 FIX_TYPE_MOVING: .db "MOVING",0 FIX_TYPE_MOVED: .db "MOVED",0 FIX_TYPE_SPEEDING: .db "SPEEDING",0 FIX_TYPE_LOCATE: .db "LOCATE",0 #ifdef OPTION_CAR_SECURITY FIX_TYPE_ALARM1: .db "ALARM 1",0 FIX_TYPE_ALARM2: .db "ALARM 2",0 FIX_TYPE_ALARM_POWER: .db "POWER LOST",0 #endif LAST_GOOD_FIX_STRING: .db ", LAST GOOD FIX ", \ 0xfd,(2<<2)+high(LAST_GOOD_FIX_LATITUDE),low(LAST_GOOD_FIX_LATITUDE)," ", \ 0xfd,((FLDLEN_GPRMC_LATITUDE-2)<<2)+high(LAST_GOOD_FIX_LATITUDE+2),low(LAST_GOOD_FIX_LATITUDE+2)," ", \ 0xfd,(FLDLEN_GPRMC_LATDIR<<2)+high(LAST_GOOD_FIX_LATDIR),low(LAST_GOOD_FIX_LATDIR)," ", \ 0xfd,(3<<2)+high(LAST_GOOD_FIX_LONGITUDE),low(LAST_GOOD_FIX_LONGITUDE)," ", \ 0xfd,((FLDLEN_GPRMC_LONGITUDE-3)<<2)+high(LAST_GOOD_FIX_LONGITUDE+3),low(LAST_GOOD_FIX_LONGITUDE+3)," ", \ 0xfd,(FLDLEN_GPRMC_LONGDIR<<2)+high(LAST_GOOD_FIX_LONGDIR),low(LAST_GOOD_FIX_LONGDIR)," AT ", \ 0xfd,(2<<2)+high(LAST_GOOD_FIX_TIME),low(LAST_GOOD_FIX_TIME),":", \ 0xfd,(2<<2)+high(LAST_GOOD_FIX_TIME+2),low(LAST_GOOD_FIX_TIME+2),":", \ 0xfd,(2<<2)+high(LAST_GOOD_FIX_TIME+4),low(LAST_GOOD_FIX_TIME+4)," UTC",0 GPS_MATCH_PATTERN: .db low(GPS_PARSE_GPRMC),high(GPS_PARSE_GPRMC),"$GPRMC",0, \ low(GPS_PARSE_GPGGA),high(GPS_PARSE_GPGGA),"$GPGGA",0, \ low(GPS_PARSE_OTHER),high(GPS_PARSE_OTHER),0 GPRMC_PARSE_STRING: .db 1,(FLDLEN_GPRMC_TIME<<2)+high(FLDADR_GPRMC_TIME),low(FLDADR_GPRMC_TIME), \ 2,(FLDLEN_GPRMC_FIXVALID<<2)+high(FLDADR_GPRMC_FIXVALID),low(FLDADR_GPRMC_FIXVALID), \ 3,(FLDLEN_GPRMC_LATITUDE<<2)+high(FLDADR_GPRMC_LATITUDE),low(FLDADR_GPRMC_LATITUDE), \ 4,(FLDLEN_GPRMC_LATDIR<<2)+high(FLDADR_GPRMC_LATDIR),low(FLDADR_GPRMC_LATDIR), \ 5,(FLDLEN_GPRMC_LONGITUDE<<2)+high(FLDADR_GPRMC_LONGITUDE),low(FLDADR_GPRMC_LONGITUDE), \ 6,(FLDLEN_GPRMC_LONGDIR<<2)+high(FLDADR_GPRMC_LONGDIR),low(FLDADR_GPRMC_LONGDIR), \ 7,(FLDLEN_GPRMC_SPEED<<2)+high(FLDADR_GPRMC_SPEED),low(FLDADR_GPRMC_SPEED), \ 8,(FLDLEN_GPRMC_COURSE<<2)+high(FLDADR_GPRMC_COURSE),low(FLDADR_GPRMC_COURSE), \ 9,(FLDLEN_GPRMC_DATE<<2)+high(FLDADR_GPRMC_DATE),low(FLDADR_GPRMC_DATE), \ 0xff GPGGA_PARSE_STRING: .db 6,(FLDLEN_GPGGA_FIXVALID<<2)+high(FLDADR_GPGGA_FIXVALID),low(FLDADR_GPGGA_FIXVALID), \ 7,(FLDLEN_GPGGA_SATS<<2)+high(FLDADR_GPGGA_SATS),low(FLDADR_GPGGA_SATS), \ 9,(FLDLEN_GPGGA_ALT<<2)+high(FLDADR_GPGGA_ALT),low(FLDADR_GPGGA_ALT), \ 0xff ; Used for SETSPEED, SETTRACK, and SETPOWER SETTINGS_PARSE_STRING: .db 1,(8<<2)+high(PARSE_FIELDS),low(PARSE_FIELDS), \ 2,(8<<2)+high(PARSE_FIELDS+8),low(PARSE_FIELDS+8), \ 3,(8<<2)+high(PARSE_FIELDS+16),low(PARSE_FIELDS+16), \ 4,(8<<2)+high(PARSE_FIELDS+24),low(PARSE_FIELDS+24), \ 5,(8<<2)+high(PARSE_FIELDS+32),low(PARSE_FIELDS+32), \ 6,(8<<2)+high(PARSE_FIELDS+40),low(PARSE_FIELDS+40), \ 7,(8<<2)+high(PARSE_FIELDS+48),low(PARSE_FIELDS+48), \ 8,(8<<2)+high(PARSE_FIELDS+56),low(PARSE_FIELDS+56), \ 0xff SETSPEED_DECODE_STRING: .db high(EEADR_SPEED_LIMIT) + (1<