]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blob - apps/lmc1/lmc1.py
mout: Make return value of rpp_mout_diag more consistent with other functions
[pes-rpp/rpp-lib.git] / apps / lmc1 / lmc1.py
1 #!/usr/bin/python3
2 # -*- coding: utf-8 -*-
3
4 # IMPORTS ######################################################################
5
6 import sys
7 if sys.version_info.major != 3:
8     sys.stderr.write(
9             "ERROR: Please run this script using Python 3.\n"
10         )
11     exit(1)
12
13 try:
14     import serial
15 except ImportError:
16     sys.stderr.write(
17             'ERROR: serial module for Python 3 is unavailable.\n'
18             'On Debian based systems run "apt-get install python3-serial"\n'
19         )
20     exit(1)
21
22 import glob
23 from os.path import abspath, dirname, join
24
25 WHERE_AM_I = abspath(dirname(__file__))
26
27
28
29 # SERIAL #######################################################################
30
31 def send_data(port, data, sim=False):
32
33     cmd = bytes(
34             'SPIMST0:4({:X},{:X})\n'.format((data>>8)&0xFF, (data)&0xFF),
35             'UTF-8'
36         )
37     result = b''
38
39     if(not sim):
40         ser = serial.Serial(port,
41             baudrate = 57600,
42             bytesize = serial.EIGHTBITS,
43             parity   = serial.PARITY_NONE,
44             stopbits = serial.STOPBITS_ONE,
45             timeout  = 0.1)
46
47         ser.open()
48         result = ser.read(1000)
49         ser.write(cmd)
50         result = ser.read(1000)
51         ser.close()
52
53     return cmd, result
54
55
56 def get_ports():
57     # Get virtual ports
58     vports  = sorted(glob.glob('/dev/ttyACM*'))
59     vports += sorted(glob.glob('/dev/ttyUSB*'))
60
61     # This doesn't return all the ports on /dev/ttyS*, as it is expected to
62     # return the must probable ports on where the device might be connected.
63     limit = 2
64     ports  = sorted(glob.glob('/dev/ttyS*'))
65     if len(ports) > limit:
66         ports = ports[:limit]
67
68     return vports + ports
69
70
71
72 # COMMAND LINE #################################################################
73
74 def cmd():
75
76     # Parse arguments
77     import argparse
78
79     parser = argparse.ArgumentParser(description='Send data to LMC1 device.')
80
81     parser.add_argument('-o', '--output', metavar='0xXXXX'     ,
82         default='0x0000'    , required=True,
83         help='16 bits value to send, bit by bit mapped to board outputs')
84
85     parser.add_argument('-p', '--port'  , metavar='/dev/ttyXXX',
86         default=get_ports()[0], required=True,
87         help='tty port to communicate with the board')
88
89     parser.add_argument('-s', '--sim'   ,
90         action='store_true',
91         help='simulate command, do not write to output port')
92
93     args = vars(parser.parse_args())
94
95     # Check data
96     try:
97         data = int(args['output'], 0)
98         if(data < 0):
99             sys.stdout.write(
100                     'WARNING: output data is negative, '
101                     'ignoring sign.\n'
102                 )
103             data = -1 * data
104         if(data > 65536):
105             sys.stdout.write(
106                     'WARNING: output data is larger than 16 bits, '
107                     'extra bits will be ignored.\n'
108                 )
109     except ValueError:
110         sys.stderr.write('ERROR: output data is not an integer literal.\n')
111         exit(1)
112
113     # Check port
114     # Note check done because existance of port, write rights,
115     # etc, are handled as exceptions.
116     port = args['port']
117     sim  = args['sim']
118
119     # Execute command
120     try:
121         cmd, result = send_data(port, data, sim)
122         sys.stdout.write('Command: {}'.format(cmd))
123         sys.stdout.write('Result : ')
124         if(sim):
125             sys.stdout.write('(none, using simulation)\n')
126         else:
127             sys.stdout.write('{}\n'.format(result))
128         exit(0)
129
130     except serial.SerialException as e:
131         sys.stderr.write('ERROR: {}.\n'.format(str(e)))
132         exit(1)
133
134
135
136 # GUI ##########################################################################
137
138 def gui():
139     try:
140         global Gtk
141         global Pango
142         from gi.repository import Gtk, Pango
143
144     except ImportError:
145         sys.stderr.write(
146                 'ERROR: Gtk3 bindings module for Python 3 is unavailable.\n'
147                 'On Debian based systems run "apt-get install python3-gi"\n'
148             )
149         exit(1)
150
151     g = LMC1()
152     Gtk.main()
153
154
155 class LMC1(object):
156     def __init__(self):
157         # Create GUI
158         self.builder = Gtk.Builder()
159         self.glade_file = join(WHERE_AM_I, 'gui.glade')
160         self.builder.add_from_file(self.glade_file)
161         go = self.builder.get_object
162
163         # Get objects
164         self.window = go('window')
165
166         self.port_list = go('port_list')
167         self.port = go('port')
168         self.send = go('send')
169
170         self.outputs = []
171         for i in range(1, 17):
172             self.outputs.append(go('out_{}'.format(i)))
173
174         self.opt_autosend = go('opt_autosend')
175         self.opt_sim = go('opt_sim')
176
177         self.log_view = go('log_view')
178         self.log_buff = go('log_buff')
179
180         # Connect signals
181         self.builder.connect_signals(self)
182
183         # Configure interface
184         self.populate_ports_cb(None, None)
185         self.port_list.set_active(0)
186
187         self.opt_autosend.set_active(True)
188
189         self.log_view.modify_font(Pango.FontDescription('DejaVu Sans Mono 9'))
190
191         self.window.connect('delete-event', lambda x,y: Gtk.main_quit())
192
193         # Everything is ready
194         self.window.show()
195
196
197     def log(self, data):
198         self.log_buff.insert_at_cursor(data)
199         cursor = self.log_buff.get_insert()
200         self.log_view.scroll_to_mark(cursor, 0.0, False, 0.0, 0.0)
201
202     def populate_ports_cb(self, widget, data=None):
203         self.port_list.get_model().clear()
204         for p in get_ports():
205             self.port_list.append_text(p)
206
207     def autosend_changed_cb(self, widget, data=None):
208         self.send.set_sensitive(not widget.get_active())
209
210     def autosend_cb(self, widget, data=None):
211         if(self.opt_autosend.get_active()):
212             self.send_cb(widget, data)
213
214     def send_cb(self, widget, data=None):
215         # Gather data
216         port = self.port.get_text()
217         if(not port):
218             error = Gtk.MessageDialog(self.window,
219                             Gtk.DialogFlags.DESTROY_WITH_PARENT,
220                             Gtk.MessageType.ERROR,
221                             Gtk.ButtonsType.CLOSE,
222                             'Please specify a communication port.'
223                         )
224             error.run()
225             error.destroy()
226             return
227
228         data = 0
229         for i in range(0, 16):
230             if(not self.outputs[i].get_active()):
231                 data |= (1 << i)
232
233         sim = self.opt_sim.get_active()
234
235         # Log data
236         self.log(('Port: {}\n'
237                   'Data:\n'
238                   '\tBinary     : {}\n'
239                   '\tHexadecimal: {}\n'
240                   '\tDecimal    : {}\n\n').format(
241                         port, bin(data), hex(data), data
242                     )
243                 )
244
245         try:
246             cmd, result = send_data(port, data, sim)
247             self.log('Command: {}\n'.format(cmd))
248             self.log('Result : ')
249             if(sim):
250                 self.log('(none, using simulation)\n')
251             else:
252                 self.log('{}\n'.format(result))
253
254         except serial.SerialException as e:
255             self.log('ERROR: {}.\n'.format(str(e)))
256         self.log('...\n\n')
257
258
259
260 if __name__ == '__main__':
261
262     if(len(sys.argv) > 1):
263         cmd()
264     else:
265         gui()
266