# Copyright (c) 2001-2004 Twisted Matrix Laboratories. # See LICENSE for details. """Rockwell Semiconductor Zodiac Serial Protocol Coded from official protocol specs (Order No. GPS-25, 09/24/1996, Revision 11) Maintainer: U{Bob Ippolito} The following Rockwell Zodiac messages are currently understood:: EARTHA\\r\\n (a hack to "turn on" a DeLorme Earthmate) 1000 (Geodesic Position Status Output) 1002 (Channel Summary) 1003 (Visible Satellites) 1011 (Receiver ID) The following Rockwell Zodiac messages require implementation:: None really, the others aren't quite so useful and require bidirectional communication w/ the device Other desired features:: - Compatability with the DeLorme Tripmate and other devices with this chipset (?) """ import struct, operator, math from twisted.internet import protocol from twisted.python import log DEBUG = 1 class ZodiacParseError(ValueError): pass class Zodiac(protocol.Protocol): dispatch = { # Output Messages (* means they get sent by the receiver by default periodically) 1000: 'fix', # *Geodesic Position Status Output 1001: 'ecef', # ECEF Position Status Output 1002: 'channels', # *Channel Summary 1003: 'satellites', # *Visible Satellites 1005: 'dgps', # Differential GPS Status 1007: 'channelmeas', # Channel Measurement 1011: 'id', # *Receiver ID 1012: 'usersettings', # User-Settings Output 1100: 'testresults', # Built-In Test Results 1102: 'meastimemark', # Measurement Time Mark 1108: 'utctimemark', # UTC Time Mark Pulse Output 1130: 'serial', # Serial Port Communication Parameters In Use 1135: 'eepromupdate', # EEPROM Update 1136: 'eepromstatus', # EEPROM Status } # these aren't used for anything yet, just sitting here for reference messages = { # Input Messages 'fix': 1200, # Geodesic Position and Velocity Initialization 'udatum': 1210, # User-Defined Datum Definition 'mdatum': 1211, # Map Datum Select 'smask': 1212, # Satellite Elevation Mask Control 'sselect': 1213, # Satellite Candidate Select 'dgpsc': 1214, # Differential GPS Control 'startc': 1216, # Cold Start Control 'svalid': 1217, # Solution Validity Control 'antenna': 1218, # Antenna Type Select 'altinput': 1219, # User-Entered Altitude Input 'appctl': 1220, # Application Platform Control 'navcfg': 1221, # Nav Configuration 'test': 1300, # Perform Built-In Test Command 'restart': 1303, # Restart Command 'serial': 1330, # Serial Port Communications Parameters 'msgctl': 1331, # Message Protocol Control 'dgpsd': 1351, # Raw DGPS RTCM SC-104 Data } MAX_LENGTH = 296 allow_earthmate_hack = 1 recvd = "" def dataReceived(self, recd): self.recvd = self.recvd + recd while len(self.recvd) >= 10: # hack for DeLorme EarthMate if self.recvd[:8] == 'EARTHA\r\n': if self.allow_earthmate_hack: self.allow_earthmate_hack = 0 self.transport.write('EARTHA\r\n') self.recvd = self.recvd[8:] continue if self.recvd[0:2] != '\xFF\x81': if DEBUG: raise ZodiacParseError('Invalid Sync %r' % self.recvd) else: raise ZodiacParseError sync, msg_id, length, acknak, checksum = struct.unpack(' self.MAX_LENGTH: raise ZodiacParseError("Invalid Header??") # empty messages pass empty strings message = '' # does this message have data ? if length: message, checksum = self.recvd[10:10+length], struct.unpack(' 0 minimize_ram = (options_list & 0x02) > 0 # (version info), (options info) return ((software_version, software_date), (minimize_rom, minimize_ram)) def decode_channels(self, message): assert len(message) == 90, "Channel Summary Message should be 51 words total (90 byte message)" ticks, msgseq, satseq, gpswk, gpsws, gpsns = struct.unpack('