diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..cb58ee4 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +gcc -I /usr/include/libusb-1.0 -I ./convenience/ -I ./getopt -shared -Wl,-soname,rtl_fm_python -o rtl_fm_python.so -fPIC rtl_fm_python.c convenience/convenience.c getopt/getopt.c -lrtlsdr diff --git a/grid.py b/grid.py new file mode 100755 index 0000000..923e3bb --- /dev/null +++ b/grid.py @@ -0,0 +1,60 @@ +#!/usr/bin/python + +import pygame +import os +from time import sleep + +#Colours +WHITE = (255,255,255) + +os.putenv('SDL_FBDEV', '/dev/fb1') +pygame.init() +pygame.mouse.set_visible(False) +lcd = pygame.display.set_mode((320, 240)) + +font_big = pygame.font.Font(None, 100) +font_small = pygame.font.Font(None, 18) + +lcd.fill((0,0,0)) +pygame.display.update() + +top_1 = (0,0,80,40); +top_2 = (80,0,80,40); +top_3 = (160,0,80,40); +top_4 = (240,0,80,40); + +pygame.draw.rect(lcd, (10,10,10), top_1, 2) +pygame.draw.rect(lcd, (10,10,10), top_2, 2) +pygame.draw.rect(lcd, (10,10,10), top_3, 2) +pygame.draw.rect(lcd, (10,10,10), top_4, 2) + +text_surface = font_small.render('DEMOD', True, WHITE) +rect = text_surface.get_rect(center=(40, 20)) +lcd.blit(text_surface, rect) + +text_surface = font_small.render('SQLCH', True, WHITE) +rect = text_surface.get_rect(center=(120, 20)) +lcd.blit(text_surface, rect) + +text_surface = font_small.render('GAIN', True, WHITE) +rect = text_surface.get_rect(center=(200, 20)) +lcd.blit(text_surface, rect) + +text_surface = font_small.render('MENU', True, WHITE) +rect = text_surface.get_rect(center=(280, 20)) +lcd.blit(text_surface, rect) + + +sql_gain_box = (0,40,32,200) + +pygame.draw.rect(lcd, (10,10,10), sql_gain_box, 2) + +for x in range(0,6): + pygame.draw.rect(lcd, (10,10,10), (32 + x * 48,40,48,80),2) + text_surface = font_big.render('%d'%x, True, WHITE) + rect = text_surface.get_rect(center=(32 + (x + .5) * 48, 80)) + lcd.blit(text_surface, rect) + +while True: + pygame.display.update() + sleep(1) diff --git a/key.py b/key.py old mode 100644 new mode 100755 index c908650..1db74c1 --- a/key.py +++ b/key.py @@ -1,8 +1,13 @@ +#!/usr/bin/python + import pygame import os from time import sleep import RPi.GPIO as GPIO - +from rtl_fm_python_thread import * + +make_rtl_fm_thread(block=False) + #Note #21 changed to #27 for rev2 Pi button_map = {23:(255,0,0), 22:(0,255,0), 27:(0,0,255), 17:(0,0,0)} @@ -22,24 +27,111 @@ lcd.fill((0,0,0)) pygame.display.update() font_big = pygame.font.Font(None, 100) +font_small = pygame.font.Font(None, 18) +dial = 0 + +dialColor = (255,255,255) + +sql = 0 + +sql_str = list("0x") + +freq = [1,6,2,5,5,0] + +freq_idx = 0 + +wasdown = 0 + +sql_gain_select = 0 + +redraw = 1 + +set_frequency(int(''.join(str(x) for x in freq) + "000")) while True: for event in pygame.event.get(): if event.type == pygame.KEYDOWN: - lcd.fill((0,0,0)) - text_surface = font_big.render(event.unicode, True, WHITE) - rect = text_surface.get_rect(center=(160,120)) - lcd.blit(text_surface, rect) - pygame.display.update() + redraw = 1 + if event.key == pygame.K_x: + freq[freq_idx] = (freq[freq_idx] + 1) % 10 + set_frequency(int(''.join(str(x) for x in freq) + "000")) + elif event.key == pygame.K_z: + freq[freq_idx] = (freq[freq_idx] - 1) % 10 + set_frequency(int(''.join(str(x) for x in freq) + "000")) + elif event.key == pygame.K_m: + wasdown = 1; + elif event.key == pygame.K_n: + if(wasdown == 1): + wasdown = 0 + freq_idx = (freq_idx + 1) % 6 + elif event.key == pygame.K_0: + sql_str.append('0') + elif event.key == pygame.K_1: + sql_str.append('1') + elif event.key == pygame.K_2: + sql_str.append('2') + elif event.key == pygame.K_3: + sql_str.append('3') + elif event.key == pygame.K_4: + sql_str.append('4') + elif event.key == pygame.K_5: + sql_str.append('5') + elif event.key == pygame.K_6: + sql_str.append('6') + elif event.key == pygame.K_7: + sql_str.append('7') + elif event.key == pygame.K_8: + sql_str.append('8') + elif event.key == pygame.K_9: + sql_str.append('9') + elif event.key == pygame.K_a: + sql_str.append('a') + elif event.key == pygame.K_b: + sql_str.append('b') + elif event.key == pygame.K_c: + sql_str.append('c') + elif event.key == pygame.K_d: + sql_str.append('d') + elif event.key == pygame.K_e: + sql_str.append('e') + elif event.key == pygame.K_f: + sql_str.append('f') + elif event.key == pygame.K_RETURN: + sql = int("".join(sql_str), 0) + if sql_gain_select: + set_gain(sql) + else: + set_squelch(sql) + sql_str = list("0x") # Scan the buttons -# for (k,v) in button_map.items(): -# if GPIO.input(k) == False: -# lcd.fill(v) -# text_surface = font_big.render('%d'%k, True, WHITE) -# rect = text_surface.get_rect(center=(160,120)) -# lcd.blit(text_surface, rect) -# pygame.display.update() -# sleep(0.1) + for (k,v) in button_map.items(): + if GPIO.input(k) == False: + redraw = 1 + if k == 27: + sql_gain_select = ~sql_gain_select + + if redraw: + lcd.fill((0,0,0)) + + for x in range(0,6): + text_surface = font_big.render('%d'%freq[x], True, WHITE) + rect = text_surface.get_rect(center=((x + .5) * 320 / 6, 80)) + lcd.blit(text_surface, rect) + + pygame.draw.rect(lcd, WHITE, (freq_idx * 320 / 6, 50, 320 / 6, 70), 1) + pygame.draw.rect(lcd, (255, 200, 10), (10,10,20, 220 * sql / 1024), 0) + + if sql_gain_select: + sql_gain_surface = font_small.render("VOL", True, WHITE) + else: + sql_gain_surface = font_small.render("SQL", True, WHITE) + rect = sql_gain_surface.get_rect(center=(25,25)) + lcd.blit(sql_gain_surface, rect) + + pygame.display.update() + redraw = 0 + + sleep(0.1) diff --git a/key_003.py b/key_003.py index 509f24c..bd8981d 100755 --- a/key_003.py +++ b/key_003.py @@ -1,8 +1,13 @@ +#!/usr/bin/python + import pygame import os from time import sleep import RPi.GPIO as GPIO - +from rtl_fm_python_thread import * + +make_rtl_fm_thread(block=False) + #Note #21 changed to #27 for rev2 Pi button_map = {23:(255,0,0), 22:(0,255,0), 27:(0,0,255), 17:(0,0,0)} @@ -42,9 +47,11 @@ while True: for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_x: - freq[freq_idx] = (freq[freq_idx] + 1) % 10 + freq[freq_idx] = (freq[freq_idx] + 1) % 10 + set_frequency(int(''.join(str(x) for x in freq) + "000")) elif event.key == pygame.K_z: freq[freq_idx] = (freq[freq_idx] - 1) % 10 + set_frequency(int(''.join(str(x) for x in freq) + "000")) elif event.key == pygame.K_m: wasdown = 1; elif event.key == pygame.K_n: @@ -85,6 +92,7 @@ while True: sql_str.append('f') elif event.key == pygame.K_RETURN: sql = int("".join(sql_str), 0) + set_squelch(sql) sql_str = list("0x") lcd.fill((0,0,0)) @@ -103,7 +111,7 @@ while True: #sql_surface = font_big.render('%d'%sql, True, WHITE) #rect = text_surface.get_rect(center=(160,140)) #lcd.blit(sql_surface, rect) - pygame.display.update() + pygame.display.update() # Scan the buttons # for (k,v) in button_map.items(): @@ -114,4 +122,3 @@ while True: # lcd.blit(text_surface, rect) # pygame.display.update() # sleep(0.1) - diff --git a/rtl_fm_python b/rtl_fm_python deleted file mode 160000 index e8d1734..0000000 --- a/rtl_fm_python +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e8d173491ff21a58cbebd0185bfb2322bba6ca4d diff --git a/rtl_fm_python.so.REMOVED.git-id b/rtl_fm_python.so.REMOVED.git-id new file mode 100644 index 0000000..f88515f --- /dev/null +++ b/rtl_fm_python.so.REMOVED.git-id @@ -0,0 +1 @@ +a899270edd156bceac4243cab7ce9286364ca7d0 \ No newline at end of file diff --git a/rtl_fm_python_common.py b/rtl_fm_python_common.py new file mode 100644 index 0000000..acd7ffa --- /dev/null +++ b/rtl_fm_python_common.py @@ -0,0 +1,141 @@ +# rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver +# Copyright (C) 2012 by Steve Markgraf +# Copyright (C) 2012 by Hoernchen +# Copyright (C) 2012 by Kyle Keen +# Copyright (C) 2013 by Elias Oenal +# Copyright (C) 2014 by Thomas Winningham +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from __future__ import print_function +import ctypes, sys +from time import sleep +from threading import Thread + +printstderr = lambda x : print(x,file=sys.stderr) + + +fm = ctypes.CDLL('./rtl_fm_python.so') +get_s_level = fm.lib_get_s_level +get_frequency = fm.lib_get_frequency +set_demod_fm = fm.lib_set_demod_fm +set_demod_wbfm = fm.lib_set_demod_wbfm +set_demod_am = fm.lib_set_demod_am +set_demod_lsb = fm.lib_set_demod_lsb +set_demod_usb = fm.lib_set_demod_usb +set_demod_raw = fm.lib_set_demod_raw +set_frequency = lambda f : fm.lib_set_frequency(ctypes.c_uint32(f)) +set_squelch = lambda l : fm.lib_set_squelch_level(ctypes.c_int(l)) +get_demod = lambda : chr(fm.lib_get_demod_mode()) +str_to_freq = fm.lib_frequency_convert + +def process_args(l): + c=len(l)+1 + argc=ctypes.c_int(c) + argv_var=ctypes.c_char_p *c + argu = ['rtl_fm'] + l + argv=argv_var(*argu) + return (argc,argv) + +def mag(value, e, suffix): + t = float('1e%s' % e) + i = int(value / float(t)) + r = int(value % float(t)) + r = str(r).rjust(e,'0') + s = "%s.%s" % (i,r) + while (s[-1]=="0" or s[-1]=="."): + if s[-1]==".": + s=s[:-1] + break + s=s[:-1] + return s + suffix + +def freq_to_str(f): + if f >= 1000000000: + return mag(f,9,'G') + if f >= 1000000: + return mag(f,6,'M') + if f >= 1000: + return mag(f,3,'K') + return str(f) + +set_freq_human = lambda f : set_frequency(str_to_freq(f)) +get_freq_human = lambda : freq_to_str(get_frequency()) + +def set_demod(c): + if c=='w' : set_demod_wbfm() + if c=='f' : set_demod_fm() + if c=='a' : set_demod_am() + if c=='l' : set_demod_lsb() + if c=='u' : set_demod_usb() + if c=='r' : set_demod_raw() + +def get_gains(): + c=fm.lib_get_tuner_gains_count() + b=(ctypes.c_int * c)() + fm.lib_get_tuner_gains(b) + return list(b) + +def set_gain(g): + fm.lib_set_real_gain(g) + +def get_gain(): + return fm.lib_get_gain() + +def get_auto_gain(): + return get_gain()==-100 + +def set_gain_human(g): + fm.lib_set_gain(g) + +def set_auto_gain(): + fm.lib_set_auto_gain() + + + +def rtl_fm(args=["--help"]): + fm.main(*process_args(args)) + +def rtl_fm_setup_and_go(args): + fm.lib_init_first() + fm.lib_process_args(*process_args(args)) + fm.lib_input_open() + fm.lib_output_open() + fm.lib_go() + +def rtl_fm_loop(): + fm.lib_loop() + +def rtl_fm_finish(): + fm.lib_stop() + fm.lib_output_close() + + +def rtl_fm_wrapped(args=["--help"]): + rtl_fm_setup_and_go(args) + try: + while True: + sleep(0.01) + except KeyboardInterrupt: + rtl_fm_finish() + + + + + + + + + + diff --git a/rtl_fm_python_common.pyc b/rtl_fm_python_common.pyc new file mode 100644 index 0000000..b20efc5 Binary files /dev/null and b/rtl_fm_python_common.pyc differ diff --git a/rtl_fm_python_thread.py b/rtl_fm_python_thread.py new file mode 100755 index 0000000..16797ce --- /dev/null +++ b/rtl_fm_python_thread.py @@ -0,0 +1,54 @@ +#!/usr/bin/python -i + +# rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver +# Copyright (C) 2012 by Steve Markgraf +# Copyright (C) 2012 by Hoernchen +# Copyright (C) 2012 by Kyle Keen +# Copyright (C) 2013 by Elias Oenal +# Copyright (C) 2014 by Thomas Winningham +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +from rtl_fm_python_common import * + +running = True +queue=[] + +def rtl_fm_thread(args): + rtl_fm_setup_and_go(args) + while running==True: + if len(queue) > 0: + queue.pop()() + sleep(1) + rtl_fm_finish() + +def make_rtl_fm_thread(args=sys.argv[1:],block=False): + t = Thread(target=rtl_fm_thread,args=(args,)) + t.daemon=True + t.start() + if block: + try: + while True: + sleep(1) + except KeyboardInterrupt: + running = False + +def stop_thread(): + running = False + + +if __name__ == "__main__": + make_rtl_fm_thread(block=False) + diff --git a/rtl_fm_python_thread.pyc b/rtl_fm_python_thread.pyc new file mode 100644 index 0000000..3f0cdc3 Binary files /dev/null and b/rtl_fm_python_thread.pyc differ diff --git a/rtl_fm_python_web.py b/rtl_fm_python_web.py new file mode 100755 index 0000000..b49089d --- /dev/null +++ b/rtl_fm_python_web.py @@ -0,0 +1,85 @@ +#!/usr/bin/python +# rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver +# Copyright (C) 2012 by Steve Markgraf +# Copyright (C) 2012 by Hoernchen +# Copyright (C) 2012 by Kyle Keen +# Copyright (C) 2013 by Elias Oenal +# Copyright (C) 2014 by Thomas Winningham +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from flask import Flask, jsonify, url_for, redirect +from rtl_fm_python_thread import * + +make_rtl_fm_thread(block=False) + +app = Flask(__name__) + +@app.route('/') +def web_root(): + return redirect(url_for('static', filename='index.html')) + +@app.route('/state') +def web_state(): + return jsonify( + { + 's_level' : get_s_level(), + 'freq_s' : get_freq_human(), + 'freq_i' : get_frequency(), + 'mod' : get_demod(), + 'gain' : get_gain(), + 'autogain' : get_auto_gain() + }) + +@app.route('/frequency/') +def web_set_frequency(f): + set_frequency(f) + return web_state() + +@app.route('/frequency/human/') +def web_set_human_frequency(f): + set_freq_human(str(f)) + return web_state() + +@app.route('/demod/') +def web_set_demod(c): + set_demod(str(c)) + return web_state() + +@app.route('/gain/') +def web_set_gain(g): + gain = int(str(g)) + set_gain(gain) + return web_state() + +@app.route('/gain/human/') +def web_set_gain_human(g): + gain = int(str(g)) + set_gain_human(gain) + return web_state() + +@app.route('/gain/auto') +def web_set_auto_gain(): + set_auto_gain() + return web_state() + +@app.route('/gain/list') +def web_get_gain_list(): + l=get_gains() + return jsonify({'gains':l}) + +if __name__ == '__main__': + app.run(host='0.0.0.0',port=10100) + stop_thread() + diff --git a/start_key.sh b/start_key.sh new file mode 100755 index 0000000..2445eab --- /dev/null +++ b/start_key.sh @@ -0,0 +1 @@ +./key.py -M fm -f 162.55M -s 32k - |aplay -r 32k -f S16_LE -t raw -c 1