def crc(msgstr, poly): if poly[0:1] != '1': raise AppError("poly %s does not start with '1'" % poly) if len(poly) < 2: raise AppError("length of poly %s is less than 2" % poly) if len(msgstr) < 1: raise AppError("length of message %s is less than 1" % msgstr) plength = len(poly) # Quotient is discarded. We may collect it for debugging #quotient = "" rem = msgstr[0:plength-1] msgstr = msgstr[plength-1:] + '0'*(plength-1) ## P3 #print 'initial rem', rem, 'rest', msgstr for i in range(0,len(msgstr)): accum = rem + msgstr[i:i+1] ## P3 #print 'acc', accum rem = xor(poly, accum) if rem[0:1] == '1': #quotient += '0' rem = accum[1:plength] else: #quotient += '1' rem = rem[1:plength] ## P3 #print " rem", rem[1:plength] ## P3 #print 'quot', quotient return rem
def cpr_decode_lat(oddstr, cprstr, ourlat): """ :param oddstr: odd/even flag as 1-char bitstr :param cprstr: the CPR of target latitude :param ourlat: the latitude of the station in float degrees :returns: the target latitude in float degrees """ Nb = 17 # 17 for airborne, 14 for ground/intent, 12 for TIS-B. NZ = 15 # Doc 9871 C.2.6.2 if len(cprstr) != Nb: raise AppError("Latitude bit string size is not 17: %d" % len(cprstr)) if oddstr != '0' and oddstr != '1': raise AppError("Invalid odd/even: %d" % oddstr) lat_s = ourlat i = btoi(oddstr) # Formulas only use the arc fraction, so convert YZ to fraction right away. YZf = float(btoi(cprstr)) / (1 << Nb) # Dlat_i is either 6.0 or 360/59==6.1016949152 Dlat_i = 360.0 / (4.0 * NZ - i) # Zone index number j = math.floor(lat_s/Dlat_i) + \ math.floor(0.5 + (lat_s % Dlat_i)/Dlat_i - YZf) Rlat = Dlat_i * (j + YZf) return Rlat
def fork_rtl_adsb(prog_path): # Unfortunately, rtl_adsb conflicts with DVB kernel modules. # Fortunately, it produces a good printout in such case. # On Fedora, do this: # echo 'blacklist dvb_usb_rtl28xxu' > /etc/modprobe.d/blacklist-dvb.conf # Elsewhere, do this: # rmmod dvb_usb_rtl28xxu # We may want to document this in the future. (pipe_r, pipe_w) = os.pipe() # Replace with os.spawnv(os.P_NOWAIT, srv_path, args) for Windows prog_pid = os.fork() if prog_pid == 0: zero_r = os.open("/dev/null", os.O_RDONLY) os.dup2(zero_r, 0) os.close(pipe_r) os.dup2(pipe_w, 1) os.execv(prog_path, [ prog_path, ]) # We're likely to receive an OSError at this point but it costs nothing. raise AppError("Exec failed for %s" % prog_path) # global prog_pid # XXX somewhere at exit maybe # import signal # os.kill(prog_pid, signal.SIGTERM) os.close(pipe_w) # What's strange, if we do the os.fdopen() like below, without # os.O_NONBLOCK, then the resulting file-like object produces # non-blocking reads (seen with strace). Magic. return os.fdopen(pipe_r, 'rb', 0)
def open_gps_tty(tty_path, tty_speed): if tty_speed == 4800: speed = termios.B4800 elif tty_speed == 9600: speed = termios.B9600 elif tty_speed == 115200: # Nobody should be crazy enough to run onboard RS-422 this fast. # We allow this because AV8OR has a firmware bug that makes it # clock 115200 after a sleep-resume. This way we don't need to # reboot the GPS each time a debugging sessing starts. speed = termios.B115200 else: raise AppError("Speed %s is invalid" % str(tty_speed)) # Must open with os.O_NONBLOCK in case DTR is not connected. fd = os.open(tty_path, os.O_RDONLY | os.O_NONBLOCK) # The parameters are a little convoluted, so we fetch an example, # then modify it to suit. We don't know an equivalent of cfmakeraw() # exists in Python (e.g. if tty.setraw() does everything necessary). # In any case, NMEA protocol is such that cooked mode suits us just fine. # Let's just kill echo, in case. ttyb = termios.tcgetattr(fd) ttyb[2] |= termios.CLOCAL ttyb[3] &= ~termios.ECHO ttyb[4] = ttyb[5] = speed termios.tcsetattr(fd, termios.TCSAFLUSH, ttyb) # (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK); return os.fdopen(fd, 'rb', 0)
def recv_event(self): # Always receive the socket data, or else the poll would loop. # Except that real sockets do not support .read(), thank you Guido #mbuf = self.sock.recv(4096) # Reading 4K does not return until filled #mbuf = self.sock.read(4096) # No size is even worse: never returns anything! #mbuf = self.sock.read() # A viable workaround: readline is responsive, albeit reading 1 byte at # a time through the OS interface. Of course it blocks until the whole # line is received. #mbuf = self.sock.readline() # Time to be brutal: just bypass the whole sorry bug-infested pile. mbuf = os.read(self.sock.fileno(), 4096) if mbuf == None: # This should not happen if poll() works correctly. raise AppError("Received None") if len(mbuf) == 0: # EOF - we do nothing and hope for a proper event in the main loop. return self.mbufs.append(mbuf) self.rcvd += len(mbuf) ## P3 #print("mbuf %d rcvd %d" % (len(mbuf), self.rcvd)) while 1: buf = recv_event_readline(self) if buf is None: break recv_msg_adsb(buf.decode('ascii', errors='replace'))
def scatter_bits(hex_chunk): nibble_decoder_tab = { '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111' } ret_bits = '' while len(hex_chunk): nibble = hex_chunk[:1] try: ret_bits += nibble_decoder_tab[nibble] except KeyError: raise AppError("Invalid nibble '%s'" % nibble) hex_chunk = hex_chunk[1:] return ret_bits
def cpr_decode_lon(oddstr, cprstr, tgtlat, ourlon): Nb = 17 # 17 for airborne, 14 for ground/intent, 12 for TIS-B. if len(cprstr) != 17: raise AppError("Longitude bit string size is not 17: %d" % len(cprstr)) if oddstr != '0' and oddstr != '1': raise AppError("Invalid odd/even: %d" % oddstr) Rlat = tgtlat lon_s = ourlon i = btoi(oddstr) XZf = float(btoi(cprstr)) / (1 << Nb) # NL() defined in AppC.2.6.2.d Note 5 nl = NL(Rlat) if nl - i == 0: Dlon_i = 360.0 else: Dlon_i = 360.0 / (nl - i) m = math.floor(lon_s/Dlon_i) + \ math.floor(0.5 + (lon_s % Dlon_i)/Dlon_i - XZf) Rlon_i = Dlon_i * (m + XZf) return Rlon_i
def recv_event(self): mbuf = os.read(self.sock.fileno(), 4096) if mbuf == None: raise AppError("Received None from UAT") if len(mbuf) == 0: return self.mbufs.append(mbuf) self.rcvd += len(mbuf) while 1: buf = recv_event_readline(self) if buf is None: break recv_msg_uat(buf.decode('ascii', errors='replace'))
def recv_event(self): mbuf = os.read(self.sock.fileno(), 4096) # XXX sometimes throws: # OSError: [Errno 11] Resource temporarily unavailable if mbuf == None: raise AppError("Received None from GPS") if len(mbuf) == 0: return self.mbufs.append(mbuf) self.rcvd += len(mbuf) while 1: buf = recv_event_readline(self) if buf is None: break ## P3 #print("nmea line", buf) recv_msg_nmea(buf.decode('ascii', errors='replace'))