├── .gitignore
├── LICENSE
├── README.md
├── echo_client.py
├── hello.py
├── images
├── LightEaster.png
└── pattern_40.gif
├── index.html
├── radio-smbus-tea5767-class.py
├── radio-smbus-tea5767.py
├── radio_server.py
├── radioweb.py
├── ss.py
├── tea5767.png
├── tea5767_tornado.html
├── tea5767_tornado_server.py
├── tea5767controller.py
├── tea5767stationscanner.py
├── telek.txt
├── websocket-other.py
├── workfile
└── wstester.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 |
26 | # PyInstaller
27 | # Usually these files are written by a python script from a template
28 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
29 | *.manifest
30 | *.spec
31 |
32 | # Installer logs
33 | pip-log.txt
34 | pip-delete-this-directory.txt
35 |
36 | # Unit test / coverage reports
37 | htmlcov/
38 | .tox/
39 | .coverage
40 | .coverage.*
41 | .cache
42 | nosetests.xml
43 | coverage.xml
44 | *,cover
45 |
46 | # Translations
47 | *.mo
48 | *.pot
49 |
50 | # Django stuff:
51 | *.log
52 |
53 | # Sphinx documentation
54 | docs/_build/
55 |
56 | # PyBuilder
57 | target/
58 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 LinuxCircle
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Raspberry Pi FM receiver using Python 3 I2C and Tea5767
2 |
3 | Contributor: Dipto Pratyaksa
4 | LinuxCircle.com
5 |
6 | Description:
7 |
8 | This is a simple TEA5767 driver to tune into a local radio station
9 | with Raspberry Pi 2. You can either use the console program or run the web interface.
10 |
11 |
12 |
13 | Running on Linux command console:
14 |
15 | sudo python3 tea5767controller.py
16 |
17 | or with sufficient permission and executable file:
18 | sudo ./tea5767controller.py
19 |
20 | Running the Web Interface
21 |
22 | Run it with: sudo python3 tea5767_tornado_server.py
23 |
24 | Open browser from a client computer: http://IPADDRESSOFYOURPI:8888
25 |
26 | Example: http:/192.168.1.2:8888
27 |
28 |
--------------------------------------------------------------------------------
/echo_client.py:
--------------------------------------------------------------------------------
1 | #from __future__ import print_function
2 | import websocket
3 |
4 | if __name__ == "__main__":
5 | websocket.enableTrace(True)
6 | ws = websocket.create_connection("ws://192.168.1.2:8888/ws")
7 | print("Sending 'Hello, World'...")
8 | ws.send("Hello, World")
9 | print("Sent")
10 | print("Receiving...")
11 | result = ws.recv()
12 | print("Received '%s'" % result)
13 | ws.close()
14 |
--------------------------------------------------------------------------------
/hello.py:
--------------------------------------------------------------------------------
1 | print("TEA5767 FM Radio project")
2 | print("dipto@linuxcircle.com")
3 | print("Excellent codes will be uploaded here!")
4 |
5 |
--------------------------------------------------------------------------------
/images/LightEaster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxCircle/tea5767/e915e11c7324a702e850768681c9a7e3e253b5c1/images/LightEaster.png
--------------------------------------------------------------------------------
/images/pattern_40.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxCircle/tea5767/e915e11c7324a702e850768681c9a7e3e253b5c1/images/pattern_40.gif
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
49 |
50 |
51 |
52 |
Raspberry Pi 2 TEA5767 Radio Tuner
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/radio-smbus-tea5767-class.py:
--------------------------------------------------------------------------------
1 | ######!/usr/bin/python3
2 | ###### # -*- coding: utf-8 -*-
3 |
4 | import smbus as smbus
5 | import subprocess
6 | import time
7 | import sys
8 |
9 | import quick2wire.i2c as i2clib
10 | from quick2wire.i2c import I2CMaster, writing_bytes, reading
11 |
12 | cof = 32768 #crystal constant
13 |
14 |
15 | class tea5767:
16 | def __init__(self):
17 | self.i2c = smbus.SMBus(1)
18 | self.bus = i2clib.I2CMaster()
19 | self.add = 0x60 # I2C address circuit
20 | self.freq = 101.9
21 |
22 | print("FM Radio Module TEA5767")
23 |
24 |
25 | def getFreq(self):
26 | # getReady()
27 | frequency = 0.0
28 | results = self.bus.transaction(
29 | reading(self.add, 5)
30 | )
31 |
32 | frequency = ((results[0][0]&0x3F) << 8) + results[0][1];
33 | # Determine the current frequency using the same high side formula as above
34 | frequency = round(frequency * 32768 / 4 - 225000) / 1000000;
35 | # print(frequency)
36 | return round(frequency,2)
37 |
38 |
39 | def calculateFrequency(self):
40 | """calculate the station frequency based upon the upper and lower bits read from the device"""
41 | repeat = 0
42 | f =0.0
43 | with i2clib.I2CMaster() as b:
44 | results = b.transaction(
45 | reading(self.add, 5)
46 | )
47 |
48 | uF = results[0][0]&0x3F
49 | lF = results[0][1]
50 | # this is probably not the best way of doing this but I was having issues with the
51 | # frequency being off by as much as 1.5 MHz
52 | current_freq = round((float(round(int(((int(uF)<<8)+int(lF))*cof/4-22500)/100000)/10)-.2)*10)/10
53 | return current_freq
54 |
55 |
56 |
57 | #script to get ready
58 | def getReady(self):
59 |
60 | readyFlag = 0
61 | i = False
62 | attempt = 0
63 | results=[]
64 | standbyFlag = 0
65 | sys.stdout.flush()
66 | time.sleep(0.1)
67 | print("Getting ready ", end ="")
68 | while (i==False):
69 | results = self.bus.transaction(
70 | reading(self.add, 5)
71 | )
72 |
73 | readyFlag = 1 if (results[0][0]&0x80)==128 else 0
74 | standbyFlag = 1 if (results[0][3]+0x40)!=319 else 0
75 |
76 | #print("result search mode:" , results[0][0]+0x40)
77 | #s = results[0][3]+0x40
78 | sys.stdout.flush()
79 | time.sleep(0.9)
80 | print(".", end = "")
81 | # print("Soft mute ", results[0][3]&0x08)
82 | #print(results[0][3]+0x40)
83 | i=standbyFlag*readyFlag
84 | attempt+=1
85 | if(attempt>10):
86 | break
87 | if(i==True):
88 | print("Ready! (",attempt,")")
89 | # print("Raw output ", results[0])
90 | else:
91 | self.i2c.read_byte(self.add)
92 | print("Not ready!")
93 |
94 | def writeFrequency(self,f, mute):
95 | freq = f # desired frequency in MHz (at 101.1 popular music station in Melbourne)
96 | cof = 32768
97 | i=False
98 | attempt = 0
99 | # Frequency distribution for two bytes (according to the data sheet)
100 | freq14bit = int (4 * (freq * 1000000 + 225000) / cof)
101 | freqH = freq14bit >>8
102 | freqL = freq14bit & 0xFF
103 |
104 | data = [0 for i in range(4)]
105 | # Descriptions of individual bits in a byte - viz. catalog sheets
106 | if(mute==0):
107 | init = freqH&0x3F# freqH # 1.byte (MUTE bit; Frequency H) // MUTE is 0x80 disable mute and search mode & 0x3F
108 | else:
109 | init = freqH&0x7F
110 | data[0] = freqL # 2.byte (frequency L)
111 | if(mute==0):
112 | data[1] = 0b10010000 # 3.byte (SUD; SSL1, SSL2; HLSI, MS, MR, ML; SWP1)
113 | else:
114 | data[1] = 0b00010110
115 | data[2] = 0b00010010 # 4.byte (SWP2; STBY, BL; XTAL; smut; HCC, SNC, SI)
116 | data[3] = 0b00000000 # 5.byte (PLREFF; DTC; 0; 0; 0; 0; 0; 0)
117 |
118 | #data[1]=0xB0; #3 byte (0xB0): high side LO injection is on,.
119 | #data[2]=0x10; #4 byte (0x10) : Xtal is 32.768 kHz
120 | #data[3]=0x00; #5 byte0x00)
121 |
122 | while (i==False):
123 | try:
124 | self.i2c.write_i2c_block_data (self.add, init, data) # Setting a new frequency to the circuit
125 | except IOError as e :
126 | i = False
127 | attempt +=1
128 | if attempt > 100000:
129 | break
130 | except Exception as e:
131 | print("I/O error: {0}".format(e))
132 |
133 | else:
134 | i = True
135 | cf = self.calculateFrequency()
136 | gf = self.getFreq()
137 | averageF =round((cf+gf)/2,2)
138 |
139 |
140 | def scan(self,direction):
141 | i=False
142 | self.freq = self.getFreq()
143 | fadd = 0
144 | while (i==False):
145 | if(direction==1):
146 | fadd+=0.05
147 | else:
148 | fadd-=0.05
149 | self.freq = self.getFreq() #round((self.calculateFrequency()+self.getFreq())/2,2)
150 | if(self.freq<87.5):
151 | self.freq=108
152 | elif(self.freq>108):
153 | self.freq=87.5
154 | self.writeFrequency(self.freq+fadd,1)
155 | time.sleep(0.1)
156 | results = self.bus.transaction(
157 | reading(self.add, 5)
158 | )
159 |
160 | readyFlag = 1 if (results[0][0]&0x80)==128 else 0
161 | level = results[0][3]>>4
162 | #print(results[0][0]&0x80 , " " , results[0][3]>>4)
163 | if(readyFlag and level>9):
164 | i=True
165 | print("Frequency tuned: ",self.calculateFrequency(), "FM (Strong Signal: ",level,")")
166 |
167 | else:
168 | i=False
169 | print("Station skipped: ",self.calculateFrequency(), "FM (Weak Signal: ",level,")")
170 |
171 | self.writeFrequency(self.calculateFrequency(),0)
172 |
173 | def off(self):
174 | print("Radio off: Goodbye now!")
175 | self.writeFrequency(self.calculateFrequency(), 1)
176 |
177 | radio = tea5767()
178 | radio.getReady()
179 | radio.scan(1)
180 | time.sleep(10)
181 | radio.scan(1)
182 | time.sleep(10)
183 | radio.scan(0)
184 | time.sleep(10)
185 | radio.scan(0)
186 | time.sleep(10)
187 | radio.off()
188 |
189 |
--------------------------------------------------------------------------------
/radio-smbus-tea5767.py:
--------------------------------------------------------------------------------
1 | ######!/usr/bin/python3
2 | ###### # -*- coding: utf-8 -*-
3 |
4 | import smbus as smbus
5 | import subprocess
6 | import time
7 | import sys
8 |
9 | from Adafruit_I2C import Adafruit_I2C
10 | import quick2wire.i2c as i2clib
11 | from quick2wire.i2c import I2CMaster, writing_bytes, reading
12 |
13 | attempt = 0
14 | output=[]
15 | bus = i2clib.I2CMaster()
16 | add = 0x60 # I2C address circuit
17 | cof = 32768
18 | i = False
19 | freq = 105.1
20 | # Frequency distribution for two bytes (according to the data sheet)
21 | freq14bit = int (4 * (freq * 1000000 + 225000) / cof)
22 | freqH = freq14bit >>8
23 | freqL = freq14bit & 0xFF
24 |
25 | data = [0 for i in range(4)]
26 | # Descriptions of individual bits in a byte - viz. catalog sheets
27 | add = 0x60 # I2C address circuit
28 | init = freqH&0x3F# freqH # 1.bajt (MUTE bit; Frequency H) // MUTE is 0x80 disable mute and search mode & 0x3F
29 |
30 | def backspace(n):
31 | # print((b'\x08' * n).decode(), end='') # use \x08 char to go back
32 | print('\r' * n, end='')
33 |
34 |
35 | i2c = smbus.SMBus(1) # newer version RASP (512 megabytes)
36 | #bus = smbus.SMBus (0) # RASP older version (256MB)
37 |
38 | def getFreq():
39 | # getReady()
40 | frequency = 0.0
41 | results = bus.transaction(
42 | reading(add, 5)
43 | )
44 |
45 | frequency = ((results[0][0]&0x3F) << 8) + results[0][1];
46 | # Determine the current frequency using the same high side formula as above
47 | frequency = round(frequency * 32768 / 4 - 225000) / 1000000;
48 | # print(frequency)
49 | return round(frequency,2)
50 |
51 |
52 | def calculateFrequency():
53 | """calculate the station frequency based upon the upper and lower bits read from the device"""
54 | #bus = smbus.SMBus (0) # RASP older version (256MB)
55 | repeat = 0
56 | f =0.0
57 | with i2clib.I2CMaster() as b:
58 | results = b.transaction(
59 | reading(add, 5)
60 | )
61 |
62 | uF = results[0][0]&0x3F
63 | lF = results[0][1]
64 | # this is probably not the best way of doing this but I was having issues with the
65 | # frequency being off by as much as 1.5 MHz
66 | current_freq = round((float(round(int(((int(uF)<<8)+int(lF))*cof/4-22500)/100000)/10)-.2)*10)/10
67 | return current_freq
68 |
69 |
70 |
71 |
72 | #import pigpio
73 |
74 | #i2c = smbus.SMBus(1) # newer version RASP (512 megabytes)
75 | #bus = smbus.SMBus (0) # RASP older version (256MB)
76 |
77 | #af = Adafruit_I2C(0x60, 1, True)
78 | #pipi = pigpio.pi()
79 |
80 |
81 |
82 | print("FM Radio Module TEA5767")
83 |
84 | #script to get ready
85 | #def getReady():
86 | readyFlag = 0
87 | i = False
88 | attempt = 0
89 | results=[]
90 | standbyFlag = 0
91 | sys.stdout.flush()
92 | time.sleep(0.1)
93 | print("Getting ready ", end ="")
94 | while (i==False):
95 | #output = i2c.read_i2c_block_data(add,init)
96 | #i2c.read_byte(add)
97 | results = bus.transaction(
98 | reading(add, 5)
99 | )
100 |
101 | readyFlag = 1 if (results[0][0]&0x80)==128 else 0
102 | standbyFlag = 1 if (results[0][3]+0x40)!=319 else 0
103 |
104 | #print("result search mode:" , results[0][0]+0x40)
105 | #s = results[0][3]+0x40
106 | sys.stdout.flush()
107 | time.sleep(0.9)
108 | print(".", end = "")
109 | # print("Soft mute ", results[0][3]&0x08)
110 | #print(results[0][3]+0x40)
111 | i=standbyFlag*readyFlag
112 | attempt+=1
113 | if(attempt>10):
114 | break
115 | if(i==True):
116 | print("Ready! (",attempt,")")
117 | # print("Raw output ", results[0])
118 | else:
119 | i2c.read_byte(add)
120 | print("Not ready!")
121 |
122 |
123 | #current_address = i2c.read_byte(add)
124 | #time.sleep(1)
125 | #getReady()
126 | time.sleep(1)
127 | print("Current frequency is " , getFreq(), "FM or ", calculateFrequency(),"FM")
128 | #current_address = i2c.read_byte(add)
129 | #print("Current address " , current_address)
130 |
131 | #writeFrequency(105.1)
132 |
133 | def writeFrequency(f, mute):
134 | freq = f # desired frequency in MHz (at 101.1 popular music station in Melbourne)
135 | cof = 32768
136 | i=False
137 | attempt = 0
138 | # Frequency distribution for two bytes (according to the data sheet)
139 | freq14bit = int (4 * (freq * 1000000 + 225000) / cof)
140 | freqH = freq14bit >>8
141 | freqL = freq14bit & 0xFF
142 |
143 | data = [0 for i in range(4)]
144 | # Descriptions of individual bits in a byte - viz. catalog sheets
145 | add = 0x60 # I2C address circuit
146 | if(mute==0):
147 | init = freqH&0x3F# freqH # 1.bajt (MUTE bit; Frequency H) // MUTE is 0x80 disable mute and search mode & 0x3F
148 | else:
149 | init = freqH&0x7F
150 | data[0] = freqL # 2.bajt (frequency L)
151 | if(mute==0):
152 | data[1] = 0b10010000 # 3.bajt (SUD; SSL1, SSL2; HLSI, MS, MR, ML; SWP1)
153 | else:
154 | data[1] = 0b00010110
155 | data[2] = 0b00010010 # 4.bajt (SWP2; STBY, BL; XTAL; smut; HCC, SNC, SI)
156 | data[3] = 0b00000000 # 5.bajt (PLREFF; DTC; 0; 0; 0; 0; 0; 0)
157 |
158 | #data[1]=0xB0; #3 byte (0xB0): high side LO injection is on,.
159 | #data[2]=0x10; #4 byte (0x10) : Xtal is 32.768 kHz
160 | #data[3]=0x00; #5 byte0x00)
161 |
162 | while (i==False):
163 | try:
164 | i2c.write_i2c_block_data (add, init,data) # Setting a new frequency to the circuit
165 | except IOError as e :
166 | #print("I/O error: {0}".format(e))
167 | i = False
168 | attempt +=1
169 | if attempt > 100000:
170 | break
171 | except Exception as e:
172 | print("I/O error: {0}".format(e))
173 |
174 | else:
175 | i = True
176 | print(attempt)
177 | # subprocess.call(['i2cdetect', '-y', '1'])
178 | # flag = 1 #optional flag to signal your code to resend or something
179 |
180 | # if (i == False):
181 | # print("Took too long to change")
182 | # else:
183 | # cf = calculateFrequency()
184 | # gf = getFreq()
185 | # averageF =(cf+gf)/2
186 | # print("Frequency changed: ", cf , " " , gf, "(",attempt,")")
187 |
188 | #writeFrequency(91.5)
189 |
190 | i=False
191 | f = getFreq()
192 | fadd = 0
193 | while (i==False):
194 | #output = i2c.read_i2c_block_data(add,init)
195 | #i2c.read_byte(add)
196 | fadd+=0.05
197 | f = (calculateFrequency()+getFreq())/2
198 | if(f<87 or f>108):
199 | f=87
200 | writeFrequency(f+fadd,1)
201 | #print(f+fadd)
202 | time.sleep(0.1)
203 | results = bus.transaction(
204 | reading(add, 5)
205 | )
206 | # time.sleep(0.1)
207 |
208 | readyFlag = 1 if (results[0][0]&0x80)==128 else 0
209 | level = results[0][3]>>4
210 | print(results[0][0]&0x80 , " " , results[0][3]>>4)
211 | if(readyFlag and level>8):
212 | i=True
213 | else:
214 | i=False
215 | #print(results[0][0]&0x40)
216 |
217 | writeFrequency((getFreq()+calculateFrequency())/2,0)
218 | print("Frequency tuned: ", calculateFrequency(), "FM")
219 |
220 |
--------------------------------------------------------------------------------
/radio_server.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | """
6 | Programmer : Dipto Pratyaksa for www.LinuxCircle.com
7 | Dependencies : tea5767stationscanner.py, index.html
8 | Original source : http://www.svesoftware.com/documents/radio_server.py
9 | Last update : 17 August 2015 - Indonesia's independence day
10 | """
11 |
12 | import sys
13 | import http
14 | from http import server
15 | import os
16 | import glob
17 | import time
18 | import datetime
19 | import tea5767stationscanner
20 | import websocket
21 | import socket
22 | import sys
23 |
24 |
25 | class MyRequestHandler(http.server.SimpleHTTPRequestHandler):
26 |
27 | tea = None
28 |
29 | def __init__(self, request, address, server):
30 | if(self.tea==None):
31 | self.tea = rr
32 | self.tea.on()
33 | http.server.SimpleHTTPRequestHandler.__init__(self, request, address, server)
34 |
35 |
36 | def do_GET(self):
37 | if self.path == '/':
38 | self.path = 'index.html'
39 | if self.path == '/searchup':
40 | self.tea.scan(1)
41 | print('search up finished')
42 | self.send_response(200)
43 | self.send_header('Content-type','text/html')
44 | #self.send_header("Content-type", "application/json")
45 | #self.send_header("Content-length", 2)
46 | self.end_headers()
47 | self.wfile.write(bytes("ok","UTF-8"))
48 | self.wfile.flush()
49 | return
50 | if self.path == '/searchdown':
51 | self.tea.scan(0)
52 | print('search down finished')
53 | self.send_response(200)
54 | self.send_header('Content-type','text/html')
55 | #self.send_header("Content-type", "application/json")
56 | #self.send_header("Content-length", 2)
57 | self.end_headers()
58 | self.wfile.write(bytes("ok","UTF-8"))
59 | self.wfile.flush()
60 | return
61 | if self.path == '/off':
62 | self.tea.off()
63 | print('radio mute')
64 | self.send_response(200)
65 | self.send_header('Content-type','text/html')
66 | #self.send_header("Content-type", "application/json")
67 | #self.send_header("Content-length", 2)
68 | self.end_headers()
69 | self.wfile.write(bytes("ok","UTF-8"))
70 | self.wfile.flush()
71 | return
72 |
73 | if self.path == '/info':
74 | resp = self.tea.info()
75 | resp = "{" + '"freq":' + resp['freq'] + ',"level":' + resp['level']+',"stereo":\"'+resp['stereo'] + "\"}"
76 | print(resp)
77 | self.send_response(200)
78 | self.send_header("Content-type", "application/json")
79 | self.send_header("Content-length", len(resp))
80 | self.end_headers()
81 | self.wfile.write(bytes(resp, 'UTF-8'))
82 | return
83 |
84 | return http.server.SimpleHTTPRequestHandler.do_GET(self)
85 |
86 |
87 | rr = tea5767stationscanner.tea5767()
88 | HandlerClass = MyRequestHandler
89 | ServerClass = http.server.HTTPServer
90 | Protocol = "HTTP/1.0"
91 |
92 |
93 |
94 | if sys.argv[1:]:
95 | port = int(sys.argv[1])
96 | else:
97 | port = 8888
98 | server_address = ('0.0.0.0', port)
99 |
100 | HandlerClass.protocol_version = Protocol
101 | httpd = ServerClass(server_address, HandlerClass)
102 |
103 | WS_PORT = 9876
104 | #ws = websocket.Websocket(WS_PORT, driver)
105 | #Thread(target=ws.serve_forever, args=(stop,)).start()
106 |
107 |
108 | try:
109 | sa = httpd.socket.getsockname()
110 | print ("Serving HTTP on ", sa[0], "port", sa[1])
111 | httpd.serve_forever()
112 | except:
113 | print("Program finished")
114 | rr.off()
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/radioweb.py:
--------------------------------------------------------------------------------
1 | import http.server
2 | import socketserver
3 |
4 | PORT = 8001
5 |
6 | Handler = http.server.SimpleHTTPRequestHandler
7 |
8 | httpd = socketserver.TCPServer(("", PORT), Handler)
9 |
10 | print("serving at port", PORT)
11 | httpd.serve_forever()
12 |
--------------------------------------------------------------------------------
/ss.py:
--------------------------------------------------------------------------------
1 | '''
2 | Simple socket server using threads
3 | '''
4 |
5 | import socket
6 | import sys
7 | import time
8 |
9 | HOST = '' # Symbolic name, meaning all available interfaces
10 | PORT = 7878 # Arbitrary non-privileged port
11 |
12 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
13 | print ('Socket created')
14 |
15 | #Bind socket to local host and port
16 | try:
17 | s.bind((HOST, PORT))
18 | except socket.error as msg:
19 | print ('Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
20 | sys.exit()
21 |
22 | print ('Socket bind complete')
23 |
24 | #Start listening on socket
25 | s.listen(10)
26 | print ('Socket now listening')
27 |
28 | def mysend(msg):
29 | totalsent = 0
30 | while totalsent < MSGLEN:
31 | sent = s.send(msg[totalsent:])
32 | if sent == 0:
33 | raise RuntimeError("socket connection broken")
34 | totalsent = totalsent + sent
35 |
36 |
37 |
38 | #now keep talking with the client
39 | while 1:
40 | #wait to accept a connection - blocking call
41 | conn, addr = s.accept()
42 | print ('Connected with ' + addr[0] + ':' + str(addr[1]))
43 | #mysend("gaga".encode('utf-8'))
44 | i = 0
45 | while 1:
46 | s.sendall(str("gagaga").encode("UTF-8"))
47 | result=conn.recv(1024)
48 | print(result)
49 | time.sleep(1)
50 |
51 | s.close()
52 |
53 | def mysend(msg):
54 | totalsent = 0
55 | while totalsent < MSGLEN:
56 | sent = s.send(msg[totalsent:])
57 | if sent == 0:
58 | raise RuntimeError("socket connection broken")
59 | totalsent = totalsent + sent
60 |
--------------------------------------------------------------------------------
/tea5767.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxCircle/tea5767/e915e11c7324a702e850768681c9a7e3e253b5c1/tea5767.png
--------------------------------------------------------------------------------
/tea5767_tornado.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
272 |
273 |
274 |
275 |
452 |
453 |
454 |
455 |
Raspberry Pi 2 TEA5767 Radio Tuner
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
--------------------------------------------------------------------------------
/tea5767_tornado_server.py:
--------------------------------------------------------------------------------
1 | import tornado.httpserver
2 | import tornado.websocket
3 | import tornado.ioloop
4 | import tornado.web
5 |
6 | import tea5767stationscanner
7 |
8 |
9 | class IndexHandler(tornado.web.RequestHandler):
10 | @tornado.web.asynchronous
11 | def get(self):
12 | self.render("tea5767_tornado.html")
13 |
14 | class WSHandler(tornado.websocket.WebSocketHandler):
15 |
16 | controller = None
17 | def check_origin(self, origin):
18 | return True
19 |
20 | def open(self):
21 | print ("connecting...")
22 | try:
23 | #self.controller = DeviceController()
24 | #self.write_message("Hello world!")
25 | self.controller=tea5767stationscanner.tea5767()
26 | self.controller.on()
27 | data=self.controller.info()
28 | self.write_message(data)
29 | # self.controller.prepareSocket()
30 | except Exception as a:
31 | print(a)
32 |
33 | def on_message(self, message):
34 | print("Command:", message)
35 | data=""
36 | try:
37 |
38 | if(message=="up"):
39 | self.controller.scan(1)
40 | elif(message=="down"):
41 | self.controller.scan(0)
42 | elif(message=="off"):
43 | data=self.controller.off()
44 | elif(message=="mute"):
45 | data=self.controller.mute()
46 | data=self.controller.info()
47 |
48 | if(message=="off"):
49 | data=self.controller.off()
50 |
51 | self.write_message(data)
52 | except Exception as a:
53 | print("Error: ", a)
54 |
55 | def on_close(self):
56 | print ("closing sockets")
57 | self.controller =""
58 |
59 |
60 | static_path = "/home/pi/Projects/tea5767/"
61 | favicon_path =""
62 |
63 | application = tornado.web.Application([
64 | (r'/favicon.ico', tornado.web.StaticFileHandler, {'path': favicon_path}),
65 | (r"/images/(.*)",tornado.web.StaticFileHandler, {"path": "./images"},),
66 | (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': static_path}),
67 | (r'/', IndexHandler),
68 | (r"/ws", WSHandler),
69 | ])
70 |
71 |
72 | if __name__ == "__main__":
73 | http_server = tornado.httpserver.HTTPServer(application)
74 | print ("Waiting client connection via browser port 8888")
75 | http_server.listen(8888)
76 | tornado.ioloop.IOLoop.instance().start()
77 |
--------------------------------------------------------------------------------
/tea5767controller.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Filename : tea5767controller.py
6 | Programmer : Dipto Pratyaksa for www.LinuxCircle.com
7 | Date / Version : August 2015. V1.0
8 | Tech : Python 3, SMBUS, i2C, TEA5767 FM Radio, Raspberry Pi 2
9 | Project : Raspberry Pi Voice command robot via FM transmitter
10 | and receiver
11 | Module : TEA5767 Radio
12 |
13 | Wish list :
14 | - Save strong stations into text file list
15 |
16 | Reference :
17 | 1. https://raw.githubusercontent.com/JTechEng/tea5767/
18 | 2. https://github.com/pcnate/fm-radio-python
19 | 3. http://www.astromik.org/raspi/38.htm
20 |
21 | Usage :
22 | sudo python3 tea5767controller.py
23 | or with executable file
24 | sudo ./tea5767controller.py
25 | """
26 |
27 |
28 |
29 | from tea5767stationscanner import tea5767
30 |
31 | a = tea5767()
32 | test =""
33 |
34 | while(test!="x"):
35 | test=input("Radio command (u)p, (d)own, (t)est, e(x)it:")
36 | if(test=="u"):
37 | a.scan(1)
38 | elif(test=="d"):
39 | a.scan(0)
40 | elif(test=="t"):
41 | a.test()
42 | elif(test=="x"):
43 | a.off()
44 |
--------------------------------------------------------------------------------
/tea5767stationscanner.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Programmer: Dipto Pratyaksa for LinuxCircle.com
6 | August 2015. Tech: Python 3, SMBUS, i2C, TEA5767 FM Radio, Raspberry Pi 2
7 | Project:Raspberry Pi Voice command robot via FM transmitter and receiver
8 | Module: Tea 5767 Station Scanner
9 | Future wish list:
10 | - Save strong stations into text file list
11 | Reference:
12 | https://raw.githubusercontent.com/JTechEng/tea5767/
13 | https://github.com/pcnate/fm-radio-python
14 | http://www.astromik.org/raspi/38.htm
15 | """
16 |
17 | import smbus as smbus
18 | import subprocess
19 | import time
20 | import sys
21 |
22 | import websocket
23 |
24 |
25 | import quick2wire.i2c as i2clib
26 | from quick2wire.i2c import I2CMaster, writing_bytes, reading
27 |
28 | cof = 32768 #crystal constant
29 |
30 | def get_bit(byteval,idx):
31 | return ((byteval&(1< 107.9:
47 | self.freq = 101.9
48 |
49 | self.signal = self.getLevel()
50 | self.stereoFlag = self.getStereoFlag()
51 | print("Last frequency = " , self.freq, "FM. Signal level = ", self.signal, " " , self.stereoFlag)
52 | self.writeFrequency(self.freq, 1, 1)
53 | # self.preparesocket()
54 | # self.ws = None
55 | def prepareSocket(self):
56 | #time.sleep(1)
57 | websocket.enableTrace(True)
58 | self.ws = websocket.create_connection("ws://192.168.1.2:8888/ws")
59 | self.ws.send('GET HTTP/1.1 200 OK\nContent-Type: text/html\n\n'.encode('utf-8'))
60 | print("Sending 'Hello, World'...")
61 | self.ws.send("Hello, World")
62 | print("Sent")
63 | print("Receiving...")
64 | result = self.ws.recv()
65 | print("Received '%s'" % result)
66 | self.ws.close()
67 | def on(self):
68 | self.writeFrequency(self.freq, 0, 0)
69 |
70 | def reset(self):
71 | #initiation
72 | if(not self.getReady()):
73 | print("resetting to default")
74 | self.i2c.write_byte(self.add, 0x00)
75 | self.getReady()
76 |
77 |
78 | def getFreq(self):
79 | frequency = 0.0
80 | results = self.bus.transaction(
81 | reading(self.add, 5)
82 | )
83 |
84 | frequency = ((results[0][0]&0x3F) << 8) + results[0][1];
85 | # Determine the current frequency using the same high side formula as above
86 | frequency = round(frequency * 32768 / 4 - 225000) / 1000000;
87 | return frequency
88 |
89 | def getLevel(self):
90 | level = 0
91 | results = self.bus.transaction(
92 | reading(self.add, 5)
93 | )
94 | level = results[0][3]>>4
95 | return level
96 |
97 | def getChipID(self):
98 | id = 0
99 | results = self.bus.transaction(
100 | reading(self.add, 5)
101 | )
102 | id = results[0][3]+0x0f
103 |
104 | return id
105 |
106 | def getStereoFlag(self):
107 | sf = 0
108 | results = self.bus.transaction(
109 | reading(self.add, 5)
110 | )
111 | sf = 1 if results[0][2]&0x80 else 0
112 | stereoflag = "stereo" if sf else "mono"
113 | return stereoflag
114 |
115 | def getTuned(self):
116 | results = self.bus.transaction(
117 | reading(self.add, 5)
118 | )
119 | elem=results[0][0]
120 | print("0 bits", int(get_bit(elem,0)), int(get_bit(elem,1)), int(get_bit(elem,2)), int(get_bit(elem,3)), int(get_bit(elem,4)), int(get_bit(elem,5)), int(get_bit(elem,6)),int(get_bit(elem,7)))
121 |
122 | elem=results[0][1]
123 | print("1 bits", int(get_bit(elem,0)), int(get_bit(elem,1)), int(get_bit(elem,2)), int(get_bit(elem,3)), int(get_bit(elem,4)), int(get_bit(elem,5)), int(get_bit(elem,6)),int(get_bit(elem,7)))
124 |
125 | elem=results[0][2]
126 | print("2 bits", int(get_bit(elem,0)), int(get_bit(elem,1)), int(get_bit(elem,2)), int(get_bit(elem,3)), int(get_bit(elem,4)), int(get_bit(elem,5)), int(get_bit(elem,6)),int(get_bit(elem,7)))
127 |
128 | elem=results[0][3]
129 | print("3 bits", int(get_bit(elem,0)), int(get_bit(elem,1)), int(get_bit(elem,2)), int(get_bit(elem,3)), int(get_bit(elem,4)), int(get_bit(elem,5)), int(get_bit(elem,6)), int(get_bit(elem,7)))
130 |
131 |
132 |
133 |
134 | return int(get_bit(elem,7))
135 |
136 |
137 |
138 | def calculateFrequency(self):
139 | """calculate the station frequency based upon the upper and lower bits read from the device"""
140 | repeat = 0
141 | f =0.0
142 | with i2clib.I2CMaster() as b:
143 | results = b.transaction(
144 | reading(self.add, 5)
145 | )
146 |
147 | uF = results[0][0]&0x3F
148 | lF = results[0][1]
149 |
150 | #good formula
151 | current_freq = round((float(round(int(((int(uF)<<8)+int(lF))*cof/4-22500)/100000)/10)-.2)*10)/10
152 | return current_freq
153 |
154 |
155 |
156 | #script to get ready
157 | def getReady(self):
158 |
159 | readyFlag = 0
160 | i = False
161 | attempt = 0
162 | results=[]
163 | standbyFlag = 0
164 | sys.stdout.flush()
165 | time.sleep(0.1)
166 | print("Getting ready ", end ="")
167 | while (i==False):
168 | results = self.bus.transaction(
169 | reading(self.add, 5)
170 | )
171 |
172 | readyFlag = 1 if (results[0][0]&0x80)==128 else 0
173 | standbyFlag = 1 if (results[0][3]&0x40)!=319 else 0
174 |
175 | sys.stdout.flush()
176 | time.sleep(0.1)
177 | print(".", end = "")
178 | i=standbyFlag*readyFlag
179 | attempt+=1
180 | if(attempt>20):
181 | break
182 | time.sleep(0.2)
183 |
184 | if(i==True):
185 | print("Ready! (",attempt,")")
186 | return True
187 | # print("Raw output ", results[0])
188 | else:
189 | self.i2c.read_byte(self.add)
190 | print("Not ready! (", attempt, ")")
191 | return False
192 |
193 | def writeFrequency(self,f, mute, direction):
194 | freq = f # desired frequency in MHz (at 101.1 popular music station in Melbourne)
195 | #cof = 32768
196 | i=False
197 | attempt = 0
198 | # Frequency distribution for two bytes (according to the data sheet)
199 | freq14bit = int (4 * (freq * 1000000 + 225000) / cof)
200 | freqH = freq14bit >>8
201 | freqL = freq14bit & 0xFF
202 |
203 | self.muteFlag = mute
204 |
205 | data = [0 for i in range(4)]
206 | # Descriptions of individual bits in a byte - viz. catalog sheets
207 | if(mute==0):
208 | init = freqH&0x3F# freqH # 1.byte (MUTE bit; Frequency H) // MUTE is 0x80 disable mute and search mode & 0x3F
209 | elif(mute==1):
210 | init = freqH&0x7F #search mode
211 | elif(mute==2):
212 | init = freqH&0x80 #mute both channels
213 | data[0] = freqL # 2.byte (frequency L)
214 | if(mute==0 and direction==1):
215 | data[1] = 0b10010000 # 3.byte (SUD; SSL1, SSL2; HLSI, MS, MR, ML; SWP1)
216 | elif(mute==0 and direction==0):
217 | data[1] = 0b00010000
218 | else:
219 | data[1] = 0b00011110 #mute L & R during scanning
220 | if(mute==0):
221 | data[2] = 0b00010000 # 4.byte (SWP2; STBY, BL; XTAL; smut; HCC, SNC, SI)
222 | else:
223 | data[2] = 0b00011111
224 | data[3] = 0b00000000 # 5.byte (PLREFF; DTC; 0; 0; 0; 0; 0; 0)
225 |
226 | #data[1]=0xB0; #3 byte (0xB0): high side LO injection is on,.
227 | #data[2]=0x10; #4 byte (0x10) : Xtal is 32.768 kHz
228 | #data[3]=0x00; #5 byte0x00)
229 |
230 | while (i==False):
231 | try:
232 | self.i2c.write_i2c_block_data (self.add, init, data) # Setting a new frequency to the circuit
233 | except IOError as e :
234 | i = False
235 | attempt +=1
236 | self.reset() #error prevention
237 | if attempt > 100000:
238 | break
239 | except Exception as e:
240 | print("I/O error: {0}".format(e))
241 | self.reset()
242 | else:
243 | i = True
244 |
245 |
246 | def scan(self,direction):
247 | i=False
248 | fadd = 0
249 | softMute = 0
250 | while (i==False):
251 | if(direction==1):
252 | fadd=0.1
253 | else:
254 | fadd=-0.1
255 | #get current frequency, more accurately by averaging 2 method results
256 | self.freq = round((self.calculateFrequency()+self.getFreq())/2,2)
257 | if(self.freq<87.5):
258 | self.freq=108
259 | elif(self.freq>107.9):
260 | self.freq=87.5
261 | self.writeFrequency(self.freq+fadd,1,direction)
262 |
263 | #give time to finish writing, and then read status
264 | time.sleep(0.03)
265 | results = self.bus.transaction(
266 | reading(self.add, 5)
267 | )
268 | self.freq = round((self.calculateFrequency()+self.getFreq())/2,2) #read again
269 |
270 | softMute = results[0][3]&0x08
271 | standbyFlag = 0 if results[0][3]&0x40 else 1
272 | self.signal = results[0][3]>>4
273 | self.stereoFlag = self.getStereoFlag()
274 | self.IFcounter = results[0][2]&0x7F
275 | self.readyFlag = 1 if results[0][3]&0x80 else 0
276 |
277 |
278 | f = open('telek.txt', 'w')
279 | f.write(str(self.freq)+"\n")
280 | # self.ws.send(self.freq)
281 | # self.serversocket.sendall(str(self.freq).encode('UTF-8'))
282 | print("Before tuning", self.getTuned())
283 | #tune into station that has strong signal only
284 | if(self.readyFlag):
285 | print("Frequency tuned:",self.freq , "FM (Strong",self.stereoFlag,"signal:",self.signal,")")
286 | else:
287 | print("Station skipped:",self.freq , "FM (Weak",self.stereoFlag,"signal:",self.signal,")")
288 | i=self.readyFlag
289 | self.writeFrequency(self.freq ,0,direction)
290 |
291 | self.readyFlag = self.getTuned()
292 | print("After tuning:", self.readyFlag)
293 |
294 | def off(self):
295 | print("Radio off")
296 | self.writeFrequency(self.calculateFrequency(), 2,0)
297 | #a = self.getMute()
298 | a = self.getTuned()
299 | print("Radio off",a)
300 | return ("radio off")
301 |
302 | def mute(self):
303 | if(self.muteFlag):
304 | self.writeFrequency(self.calculateFrequency(), 0,0)
305 | print("unmute")
306 | else:
307 | self.writeFrequency(self.calculateFrequency(), 1,0)
308 | print("mute")
309 | return ("radio muted")
310 |
311 |
312 | def test(self):
313 | print("Testing mode")
314 | print("Scanning up...")
315 | self.scan(1)
316 | print("Listening for 10 seconds")
317 | time.sleep(10)
318 | print("Scanning down...")
319 | self.scan(0)
320 | print("Listening for 10 seconds")
321 | time.sleep(10)
322 | print("done")
323 |
324 | def info(self):
325 | data ={}
326 | data['freq'] = str(self.freq)
327 | data['level'] = self.signal
328 | data['stereo'] = str(self.stereoFlag)
329 | data['tuned'] = self.readyFlag
330 | data['mute'] = self.muteFlag
331 |
332 | print(data)
333 | return data
334 | #sample usage below:
335 | #radio = tea5767()
336 | #radio.scan(1)
337 | #time.sleep(15)
338 | #radio.scan(1)
339 | #time.sleep(15)
340 | #radio.scan(0)
341 | #time.sleep(15)
342 | #radio.scan(0)
343 | #time.sleep(15)
344 | #radio.off()
345 |
346 |
--------------------------------------------------------------------------------
/telek.txt:
--------------------------------------------------------------------------------
1 | 89.9
2 |
--------------------------------------------------------------------------------
/websocket-other.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | """
4 | A partial implementation of RFC 6455
5 | http://tools.ietf.org/pdf/rfc6455.pdf
6 | Brian Thorne 2012
7 |
8 | TODO:
9 | - support long messages and multipacket frames
10 | - closing handshake
11 | - ping/pong
12 | """
13 |
14 | import socket
15 | import threading
16 | import time
17 | import base64
18 | import hashlib
19 | import textwrap
20 | import select
21 |
22 | # for python2:
23 | import struct
24 |
25 | def calculate_websocket_hash(key):
26 | magic_websocket_string = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
27 | result_string = key + magic_websocket_string
28 | sha1_digest = hashlib.sha1(result_string).digest()
29 | response_data = base64.encodestring(sha1_digest).strip()
30 | response_string = response_data.decode('utf8')
31 | return response_string
32 |
33 | def is_bit_set(int_type, offset):
34 | """
35 | >>> is_bit_set(1, 0)
36 | True
37 | >>> is_bit_set(2, 0)
38 | False
39 | >>> is_bit_set(0xFF, 2)
40 | True
41 |
42 | """
43 | mask = 1 << offset
44 | return not 0 == (int_type & mask)
45 |
46 | def set_bit(int_type, offset):
47 | """
48 | >>> set_bit(2, 0)
49 | 3
50 | """
51 | return int_type | (1 << offset)
52 |
53 | def bytes_to_int(data):
54 | """Convert a bytes/str/list to int.
55 |
56 | >>> bytes_to_int(b"a0")
57 | 24880
58 |
59 | Passed a list with null bytes:
60 |
61 | >>> bytes_to_int([97, 48])
62 | 24880
63 |
64 | Passed a string:
65 |
66 | >>> bytes_to_int("a")
67 | 97
68 | """
69 | # note big-endian is the standard network byte order
70 | try:
71 | return int.from_bytes(data, byteorder='big')
72 | except:
73 | # PYTHON2 HACK...
74 | if type(data) == str:
75 | return sum(ord(c) << (i * 8) for i, c in enumerate(data[::-1]))
76 | else:
77 | return sum(c << (i * 8) for i, c in enumerate(data[::-1]))
78 |
79 |
80 | def int_to_bytes(number, bytesize):
81 | """Convert an integer to a bytearray.
82 |
83 | The integer is represented as an array of bytesize. An OverflowError
84 | is raised if the integer is not representable with the given number
85 | of bytes.
86 |
87 | >>> int_to_bytes(97, 1)
88 | bytearray(b'a')
89 |
90 | >>> int_to_bytes(159487778, 2)
91 | Traceback (most recent call last):
92 | ...
93 | OverflowError: Need more bytes to represent that number
94 |
95 | >>> int_to_bytes(159487778, 4) == bytearray([9, 129, 151, 34])
96 | True
97 |
98 | """
99 | try:
100 | return bytearray(number.to_bytes(bytesize, byteorder='big'))
101 | except:
102 | # PYTHON2 HACK...
103 | d = bytearray(bytesize)
104 | # Use big endian byteorder
105 | fmt = '!' + {1: 'b', 2: 'H', 4: 'L', 8: 'Q'}[bytesize]
106 | try:
107 | struct.pack_into(fmt, d, 0, number)
108 | except:
109 | raise OverflowError("Need more bytes to represent that number")
110 | return d
111 |
112 |
113 | def pack(data):
114 | """pack bytes for sending to client"""
115 | frame_head = bytearray(2)
116 |
117 | # set final fragment
118 | frame_head[0] = set_bit(frame_head[0], 7)
119 |
120 | # set opcode 1 = text
121 | frame_head[0] = set_bit(frame_head[0], 0)
122 |
123 | # payload length
124 | if len(data) < 126:
125 | frame_head[1] = len(data)
126 | elif len(data) < ((2**16) - 1):
127 | # First byte must be set to 126 to indicate the following 2 bytes
128 | # interpreted as a 16-bit unsigned integer are the payload length
129 | frame_head[1] = 126
130 | frame_head += int_to_bytes(len(data), 2)
131 | elif len(data) < (2**64) -1:
132 | # Use 8 bytes to encode the data length
133 | # First byte must be set to 127
134 | frame_head[1] = 127
135 | frame_head += int_to_bytes(len(data), 8)
136 |
137 | # add data
138 | frame = frame_head + data.encode('utf-8')
139 | #print(list(hex(b) for b in frame))
140 | return frame
141 |
142 | def receive(s):
143 | """blocking call to receive data from client"""
144 |
145 | # read the first two bytes
146 | frame_head = s.recv(2)
147 |
148 | # On severed connection
149 | if frame_head == '' or frame_head == b'':
150 | return
151 |
152 | # PYTHON2 HACK
153 | frame_head = bytearray(frame_head)
154 |
155 | # very first bit indicates if this is the final fragment
156 | #print("final fragment: ", is_bit_set(frame_head[0], 7))
157 |
158 | # bits 4-7 are the opcode (0x01 -> text)
159 | #print("opcode: ", frame_head[0] & 0x0f)
160 |
161 | # mask bit, from client will ALWAYS be 1
162 | #assert is_bit_set(frame_head[1], 7)
163 |
164 | # length of payload
165 | # 7 bits, or 16 bits, 64 bits
166 | payload_length = frame_head[1] & 0x7F
167 | if payload_length == 126:
168 | raw = s.recv(2)
169 | payload_length = bytes_to_int(raw)
170 | elif payload_length == 127:
171 | raw = s.recv(8)
172 | payload_length = bytes_to_int(raw)
173 | #print('Payload is {} bytes'.format(payload_length))
174 |
175 | """masking key
176 | All frames sent from the client to the server are masked by a
177 | 32-bit nounce value that is contained within the frame
178 | """
179 | # PYTHON2 HACK
180 | masking_key = bytearray(s.recv(4))
181 | #print("mask: ", masking_key, bytes_to_int(masking_key))
182 |
183 | # finally get the payload data:
184 | bytes_received = 0
185 | masked_data_in = bytearray(payload_length)
186 | while bytes_received < payload_length:
187 | data_in = bytearray(s.recv(payload_length))
188 | #print "Received {} bytes".format(len(data_in))
189 | masked_data_in[bytes_received:bytes_received+len(data_in)] = data_in
190 |
191 | bytes_received += len(data_in)
192 | #print "Done received {} bytes".format(len(masked_data_in))
193 |
194 | data = bytearray(payload_length)
195 |
196 | # The ith byte is the XOR of byte i of the data with
197 | # masking_key[i % 4]
198 | for i, b in enumerate(masked_data_in):
199 | data[i] = b ^ masking_key[i%4]
200 |
201 | return data
202 |
203 | class Websocket(object):
204 | """
205 |
206 | """
207 |
208 | def __init__(self, port, new_client_callback=None):
209 | self.port = port
210 | self.callback = new_client_callback
211 |
212 |
213 | def serve_forever(self, end=None):
214 | """
215 | end is an optional event to trigger server shutdown
216 | """
217 | self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
218 |
219 | self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
220 | self.s.bind(('', self.port))
221 | self.s.listen(1)
222 |
223 | # because socket.accept is blocking we use select for its timeout
224 | # so every second we check if "forever" is over.
225 |
226 | while True:
227 | r, w, e = select.select((self.s,), (), (), 1)
228 | for l in r:
229 | t, address = self.s.accept()
230 | print("Accepting connection from {}:{}".format(*address))
231 | threading.Thread(target=self.handle_connection, args = (t, )).start()
232 | else:
233 | # should we quit?
234 | if end is not None and end.is_set():
235 | return
236 |
237 |
238 | def transmit(self, msg_str):
239 | self.s.send(pack(msg_str))
240 |
241 | def handle_connection(self, s):
242 | client_request = s.recv(4096)
243 | key = None
244 | # get to the key
245 | for line in client_request.splitlines():
246 | #print(line.strip())
247 | if b'Sec-WebSocket-Key:' in line:
248 | key = line.split(b': ')[1]
249 | break
250 | if key is None:
251 | raise IOError("Couldn't find the key?\n\n", client_request)
252 |
253 | response_string = calculate_websocket_hash(key)
254 |
255 | header = '''HTTP/1.1 101 Switching Protocols\r
256 | Upgrade: websocket\r
257 | Connection: Upgrade\r
258 | Sec-WebSocket-Accept: {}\r
259 | \r
260 | '''.format(response_string)
261 |
262 | s.send(header.encode())
263 |
264 | if self.callback is not None:
265 | self.callback(s)
266 |
267 |
268 | def __del__(self):
269 | self.s.close()
270 |
271 |
272 | if __name__ == "__main__":
273 | import doctest
274 | doctest.testmod()
--------------------------------------------------------------------------------
/workfile:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinuxCircle/tea5767/e915e11c7324a702e850768681c9a7e3e253b5c1/workfile
--------------------------------------------------------------------------------
/wstester.py:
--------------------------------------------------------------------------------
1 | import websocket
2 | try:
3 | import thread
4 | except ImportError: #TODO use Threading instead of _thread in python3
5 | import _thread as thread
6 | import time
7 | import sys
8 |
9 |
10 | def on_message(ws, message):
11 | print(message)
12 |
13 |
14 | def on_error(ws, error):
15 | print(error)
16 |
17 |
18 | def on_close(ws):
19 | print("### closed ###")
20 |
21 |
22 | def on_open(ws):
23 | def run(*args):
24 | for i in range(3):
25 | # send the message, then wait
26 | # so thread doesnt exit and socket
27 | # isnt closed
28 | ws.send("Hello %d" % i)
29 | time.sleep(1)
30 |
31 | time.sleep(1)
32 | ws.close()
33 | print("Thread terminating...")
34 |
35 | thread.start_new_thread(run, ())
36 |
37 | if __name__ == "__main__":
38 | websocket.enableTrace(True)
39 | if len(sys.argv) < 2:
40 | host = "ws://echo.websocket.org/"
41 | else:
42 | host = sys.argv[1]
43 | ws = websocket.WebSocketApp(host,
44 | on_message = on_message,
45 | on_error = on_error,
46 | on_close = on_close)
47 | ws.on_open = on_open
48 | ws.run_forever()
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------