-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathreadout_server
executable file
·147 lines (113 loc) · 3.56 KB
/
readout_server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env python3
"""
Graphical interface to control the Galton board hardware
and update the counters file for the web server
"""
import os
# Counters file location
COUNTERS_FILE = '/var/www/html/galton_counts.txt'
if not os.access(COUNTERS_FILE, os.W_OK):
COUNTERS_FILE = '/tmp/galton_counts.txt'
with open(COUNTERS_FILE,'w') as f:
f.write('a,0,0,0,0,0,0,0,0,0,0,0,0,0,x\n')
# Number of counters
N = 13
from galton.readout import GaltonBoardRead
galton = GaltonBoardRead()
import sys
from os import uname
import matplotlib as mpl
mpl.rcParams['toolbar'] = 'None'
import matplotlib.patches as patches
import matplotlib.pyplot as plt
#### Initial plot configuration ###
# matplotlib figure and axis are global objects
# physical size of RPi touchscreen
fig = plt.figure(figsize=(3.4,6.1))
ax = plt.subplot()
def server_state():
"""Provide the raw contents of the counters file"""
with open(COUNTERS_FILE, 'r') as f:
state = f.read()
return state
def state2int(state):
"""Convert counters string to integers"""
res = state.split(',')[1:-1]
res = map(int,res)
return res
def pretty_state(state):
"""Prettier string for presentation"""
return 'Server: %s' % state
init_state = server_state()
data_plot, = plt.plot(list(range(N)),list(state2int(init_state)),'ok')
count_text = plt.text(0.2,0.02,
pretty_state(init_state),
color='k',
fontsize=12,
transform=fig.transFigure,
clip_on=False
)
#####################################
#### Main functionality is here
#####################################
def update_data():
"""Get data string from the machine, update plot and server"""
# read new count from hardware
count = galton.numeric_count()
# update server file
count_str = galton.formatted_count()
with open(COUNTERS_FILE,'w') as f:
f.write(count_str + '\n')
# upate plot
data_plot.set_data(range(N),count)
ax.relim()
ax.autoscale_view()
count_text.set_text(pretty_state(server_state()))
plt.draw()
def reset_data():
"""Reset machine counter to 0, update plot and server"""
galton.reset_counters()
update_data()
#### Event handlers
# quit with keyboard q
def key_press(event):
if event.key == 'q':
sys.exit(0)
fig.canvas.mpl_connect('key_press_event', key_press)
class ActionDict(dict):
"""Map from pickable patch to function. Default does nothing."""
def __missing__(self, key):
def do_nothing(): pass
return do_nothing
action = ActionDict()
def connect(patch, fn):
action[patch] = fn
ax.add_patch(patch)
common_config = {
'picker' : 1,
'transform' : fig.transFigure,
'clip_on' : False,
}
# Off switch
button_off = patches.Circle((0.1,0.1), 0.1, color='red', **common_config)
connect(button_off, lambda: sys.exit(0))
# Update switch
button_update = patches.Circle((0.25, 0.75), 0.2, color='blue', **common_config)
connect(button_update, update_data)
# Reset switch
button_reset = patches.Circle((0.75, 0.75), 0.2, color='orange', **common_config)
connect(button_reset, reset_data)
fig.canvas.mpl_connect('pick_event', lambda ev: action[ev.artist]() )
######### label the switches
textstyle ={
'color' : 'cyan',
'fontsize' : 24,
'transform' : fig.transFigure,
}
plt.text(0.17, 0.75, 'update', **textstyle)
plt.text(0.7, 0.75, 'reset', **textstyle)
#### set fullscreen if we're on the rpi3
if uname()[4][:3] == 'arm':
mgr = plt.get_current_fig_manager()
mgr.full_screen_toggle()
plt.show()