forked from mahdanahmad/vistephen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserial_plot.py
161 lines (121 loc) · 5.27 KB
/
serial_plot.py
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# Real time plot of serial data
#
# Copyright (C) 2012 Asaf Paris Mandoki http://asaf.pm
#
# 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 3 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 <http://www.gnu.org/licenses/>.
import pygame
from pygame.locals import *
from numpy import array, arange, zeros, roll
import threading
from serial import Serial
from struct import unpack
import sys
pygame.init()
global lock
lock = threading.Lock()
""" serial data structure:
For synchronization purposes, the following scheme was chosen:
A0 data: A09 (MSB) A08 A07 A06 A05 A04 A03 A02 A01 A00 (LSB)
sent as byte 1: 1 1 1 A09 A08 A07 A06 A05
and byte 2: 0 1 1 A04 A03 A02 A01 A00
byte 1 A0 5 most significant bits + 224 (128+64+32), legitimate values are between 224 and 255
byte 2 A0 5 least significant bits + 96 (64+32) , legitimate values are between 96 and 127
"""
class DataReader(threading.Thread):
#Thread event, stops the thread if it is set.
stopthread = threading.Event()
def __init__(self):
threading.Thread.__init__(self) #Call constructor of parent
self.ser = Serial("/dev/ttyACM1",115200) #Initialize serial port
self.data_buff_size = 200 #Buffer size
self.data = zeros(self.data_buff_size) #Data buffer
self.start()
def run(self): #Run method, this is the code that runs while thread is alive.
num_bytes = 400 #Number of bytes to read at once
val = 0 #Read value
while not self.stopthread.isSet() :
rslt = self.ser.read(num_bytes) #Read serial data
byte_array = unpack('%dB'%num_bytes,rslt) #Convert serial data to array of numbers
first = False #Flag to indicate weather we have the first byte of the number
for byte in byte_array:
if 224 <= byte <= 255: #If first byte of number
val = (byte & 0b11111) << 5
first = True
elif 96 <= byte <= 127: #If second byte of number
val |= (byte & 0b11111)
if first:
lock.acquire()
self.data = roll(self.data,-1)
self.data[-1] = val
lock.release()
self.ser.close()
def stop(self):
self.stopthread.set()
class Oscilloscope():
def __init__(self):
self.screen = pygame.display.set_mode((640, 480))
self.clock = pygame.time.Clock()
self.data_reader = DataReader()
self.run()
def plot(self, x, y, xmin, xmax, ymin, ymax):
w, h = self.screen.get_size()
x = array(x)
y = array(y)
#Scale data
xspan = abs(xmax-xmin)
yspan = abs(ymax-ymin)
xsc = 1.0*(w+1)/xspan
ysc = 1.0*h/yspan
xp = (x-xmin)*xsc
yp = h-(y-ymin)*ysc
#Draw grid
for i in range(10):
pygame.draw.line(self.screen, (210, 210, 210), (0,int(h*0.1*i)), (w-1,int(h*0.1*i)), 1)
pygame.draw.line(self.screen, (210, 210, 210), (int(w*0.1*i),0), (int(w*0.1*i),h-1), 1)
#Plot data
for i in range(len(xp)-1):
pygame.draw.line(self.screen, (0, 0, 255), (int(xp[i]), int(yp[i])),
(int(xp[i+1]),int(yp[i+1])), 1)
def run(self):
#Things we need in the main loop
font = pygame.font.Font(pygame.font.match_font(u'mono'), 20)
data_buff_size = self.data_reader.data_buff_size
hold = False
while 1:
#Process events
event = pygame.event.poll()
if event.type == pygame.QUIT:
pygame.quit()
self.data_reader.stop()
sys.exit()
if event.type == pygame.KEYDOWN :
if event.key == pygame.K_h:
hold = not hold
self.screen.fill((255,255,255))
# Plot current buffer
if not hold:
lock.acquire()
x = arange(data_buff_size)
y = self.data_reader.data
lock.release()
self.plot(x,y, 0, data_buff_size, 0, 1024)
# Display fps
text = font.render("%d fps"%self.clock.get_fps(), 1, (0, 10, 10))
self.screen.blit(text, (10, 10))
pygame.display.flip()
self.clock.tick(0)
osc = Oscilloscope()