~scirocco22/rpyutils/trunk

« back to all changes in this revision

Viewing changes to rpyterm

  • Committer: Maximilian Mühlbauer
  • Date: 2013-01-26 07:15:50 UTC
  • Revision ID: git-v1:45da847780e6eb4364c10e164b319f1204c7bf9c
First code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python3
 
2
# coding=UTF-8
 
3
 
 
4
'''
 
5
rpyterm - Control your RP6 robot
 
6
Copyright (C) 2011 Scirocco <rpyutils@t-online.de>
 
7
 
 
8
This program is free software: you can redistribute it and/or modify
 
9
it under the terms of the GNU General Public License as published by
 
10
the Free Software Foundation, either version 3 of the License, or
 
11
(at your option) any later version.
 
12
 
 
13
This program is distributed in the hope that it will be useful,
 
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
GNU General Public License for more details.
 
17
 
 
18
You should have received a copy of the GNU General Public License
 
19
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
'''
 
21
 
 
22
"""rpyutils by Maximilian Mühlbauer <rpyutils@t-online.de>"""
 
23
 
 
24
import serial
 
25
import sys
 
26
import os
 
27
import getopt
 
28
import fcntl
 
29
import time
 
30
import curses
 
31
import signal
 
32
import gettext
 
33
import readline
 
34
from rpyutils.translation import _
 
35
 
 
36
def quit(signum, frame): #Strg+C abfangen. Ideen, wie man curses beenden kann?
 
37
    pass
 
38
 
 
39
signal.signal(signal.SIGINT, quit)#signal "connecten"
 
40
 
 
41
VERSION = "0.1"
 
42
 
 
43
print(_("Robby pyTerm version ")+VERSION) #immer version ausgeben
 
44
print("")
 
45
print("rpyutils Copyright (C) 2011 Scirocco <rpyutils@t-online.de>")
 
46
print("This program comes with ABSOLUTELY NO WARRANTY; for details please visit http://www.gnu.org/licenses/gpl.html")
 
47
print("This is free software, and you are welcome to redistribute it under certain conditions; visit http://www.gnu.org/licenses/gpl.html for details.")
 
48
print("")
 
49
 
 
50
def getargs(argv): #funktion, um parameter auszulesen
 
51
    global port #port ist global
 
52
    port = "/dev/ttyUSB0" #standard-port
 
53
    try: #optionen versuchen
 
54
        opts, args = getopt.getopt(argv, "d:", ["device="]) #optionen auslesen
 
55
    except getopt.GetoptError: #falsche option?
 
56
        print("Wrong option.")
 
57
    for opt, arg in opts: #wenn optionen
 
58
        if opt in ("-d", "--device"): #device
 
59
            print(arg)
 
60
            port = arg #port auf device setzen
 
61
 
 
62
getargs(sys.argv[1:])#1.arg (rpyTerm.py) nicht
 
63
 
 
64
 
 
65
# make stdin a non-blocking file
 
66
fd = sys.stdin.fileno()
 
67
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
 
68
fcntl.fcntl(fd, fcntl.F_SETFL, fl |os.O_NONBLOCK)
 
69
pipe_name = '/tmp/pypipe' #pipe zwischen robby auslesen und prog
 
70
 
 
71
def robbytopipe():
 
72
    pipeout = os.open(pipe_name, os.O_WRONLY)#pipe öffnen
 
73
    try: #Port öffnen
 
74
        ser = serial.Serial(
 
75
         port=port, #Port
 
76
         baudrate=38400, #baud
 
77
         timeout=1, #timeout
 
78
         parity=serial.PARITY_NONE, #keine Parität
 
79
         stopbits=serial.STOPBITS_ONE, #ein stopbit
 
80
         bytesize=serial.EIGHTBITS #acht bits
 
81
        )
 
82
    except: #Port existiert nicht
 
83
        print(port+_(": No such a device."))
 
84
        exit(2)
 
85
 
 
86
    time.sleep(0.5)#reset
 
87
    ser.setRTS(0) #rts aus
 
88
    while True:
 
89
        s = ser.read(1)#char von robby lesen &
 
90
        os.write(pipeout, s)#ueber pipe weiterleiten
 
91
 
 
92
def termtorobby(pid):
 
93
    histfile = "rpyTermhistory" #history fuer session in datei speichern
 
94
    rpyUtilsdir = ".rpyUtils"#verstecktes verzeichnis
 
95
 
 
96
    histpath = os.environ['HOME']+ os.sep +rpyUtilsdir + os.sep + histfile #linux: ~/.rpyUtils/rpyTermhistory
 
97
    if not os.path.exists(os.environ['HOME']+ os.sep+rpyUtilsdir): #verzeichnis existiert nicht?
 
98
        os.mkdir(os.environ['HOME']+ os.sep+rpyUtilsdir)#anlegen
 
99
    if not os.path.isfile(histpath):
 
100
        f = open(histpath, "a")
 
101
        f.close()
 
102
    histcounter = 0
 
103
    hist = open(histpath, "r")
 
104
    for line in hist:
 
105
        histcounter = histcounter + 1
 
106
    hist.close()
 
107
    readline.read_history_file(histpath)
 
108
    ser = serial.Serial(#serial port zu robby oeffnen
 
109
    port=port, #Port
 
110
    baudrate=38400, #baud
 
111
    timeout=1, #timeout
 
112
    parity=serial.PARITY_NONE, #keine
 
113
    stopbits=serial.STOPBITS_ONE, #ein stopbit
 
114
    bytesize=serial.EIGHTBITS #acht bits
 
115
    )
 
116
    ser.setRTS(0) #rts aus
 
117
 
 
118
    time.sleep(0.2) #anderem prog zeit lassen
 
119
    pipein = open(pipe_name, "r")#pipe oeffnen
 
120
    fl = fcntl.fcntl(pipein, fcntl.F_GETFL)#pipein
 
121
    fcntl.fcntl(pipein, fcntl.F_SETFL, fl |os.O_NONBLOCK)#nonblocking machen
 
122
 
 
123
    stdscr = curses.initscr()#start
 
124
    curses.noecho()# Keine Anzeige gedrückter Tasten
 
125
    curses.cbreak()# Kein line-buffer -> kann eingreifen
 
126
    stdscr.keypad(1)# Escape-Sequenzen aktivieren
 
127
 
 
128
    # Farben
 
129
    curses.start_color()
 
130
    curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLUE)
 
131
    curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_WHITE)
 
132
    curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE)
 
133
 
 
134
    # Fenster und Hintergrundfarben
 
135
    stdscr.bkgd(curses.color_pair(1))
 
136
    stdscr.refresh()
 
137
 
 
138
    termy, termx = stdscr.getmaxyx() #groesse von terminalfenster ermitteln
 
139
 
 
140
    win = curses.newwin((termy-4), termx, 0, 0)#groesse: max. breite, unten 4 uebrig lassen
 
141
    win.bkgd(curses.color_pair(2))
 
142
    win.box()
 
143
    win.refresh()
 
144
 
 
145
    win2 = curses.newwin(4, termx, (termy-4), 0)#groesse: max. breite, vier unterste zeilen
 
146
    win2.box()
 
147
    win2.bkgd(curses.color_pair(3))
 
148
    win2.keypad(1) #fuer key_up etc
 
149
 
 
150
    win.refresh()
 
151
    win2.timeout(0)#non-blocking lesen: keine daten -> -1
 
152
    win2.refresh()
 
153
    win2.addstr(1, 2, _("Please Enter your command (help for a list of built-in commands): "))
 
154
    win2.addstr(2, 2, "")
 
155
    win2.refresh()
 
156
    pad_height = 10000
 
157
    pad = curses.newpad(pad_height, 1000)#pad fuer term
 
158
    maxy, maxx = win.getmaxyx()#groesse von win1 ermitteln
 
159
 
 
160
    # Wir merken uns, wo wir sind -> scrollen
 
161
    line_start = 1
 
162
    col_start = 1
 
163
 
 
164
    i=2 #pad bei 2.Zeile anfangen
 
165
    zeile = ">> " #von robby : >> am anfang, z.B.( >> [RP6BOOT] )
 
166
    line = "" #von tastatur: leerer string
 
167
    pad.addstr(1, 2, _("Robby pyTerm version ")+str(VERSION)) #begruessung
 
168
    pad.refresh(line_start, col_start, 1, 1, maxy-2, maxx-2) #pad updaten
 
169
    exit = 0 #bei 1 exit
 
170
    cur_histcounter = histcounter
 
171
    while True and exit == 0:
 
172
        try:
 
173
            read = pipein.read(1)#IOError wenn keine Daten
 
174
            zeile += read#Byte dem String anfügen
 
175
            if read == "\n":#EOL
 
176
                pad.addstr(i, 2, zeile)#aufs pad schreiben
 
177
                line_start = i-maxy+4
 
178
                pad.refresh(line_start, col_start, 1, 1, maxy-2, maxx-2)#pad, wenn noetig, verschieben
 
179
                i=i+1
 
180
                zeile = ">> "#zeile leeren
 
181
        except IOError:
 
182
            pass #nop()
 
183
        if i > pad_height -2:
 
184
            pad.erase()
 
185
            i = 0
 
186
        char = win2.getch() #user-input einlesen
 
187
        if char != -1: #char wartet!
 
188
            if char == curses.KEY_BACKSPACE: #127:#loeschtaste
 
189
                win2.delch()#char loeschen
 
190
                line = line[0:(len(line)-1)]#von line letzten char loeschen
 
191
                win2.clear()
 
192
                win2.box()
 
193
                win2.addstr(1, 2, _("Please Enter your command (help for a list of built-in commands): "))
 
194
                win2.addstr(2, 2, line)
 
195
                win2.refresh() #refreshen
 
196
            elif char == curses.KEY_UP:
 
197
                cur_histcounter = cur_histcounter - 1
 
198
                win2.clear()
 
199
                win2.box()
 
200
                win2.addstr(1, 2, _("Please Enter your command (help for a list of built-in commands): "))
 
201
                line = readline.get_history_item(cur_histcounter)
 
202
                #print(cur_histcounter)
 
203
                if(line == None):
 
204
                    curses.beep()
 
205
                    line = ""
 
206
                    cur_histcounter = cur_histcounter + 1
 
207
                win2.addstr(2, 2, line)
 
208
                win2.refresh() #refreshen
 
209
            elif char == curses.KEY_DOWN:
 
210
                cur_histcounter = cur_histcounter + 1
 
211
                win2.clear()
 
212
                win2.box()
 
213
                win2.addstr(1, 2, _("Please Enter your command (help for a list of built-in commands): "))
 
214
                line = readline.get_history_item(cur_histcounter)
 
215
                #print(cur_histcounter)
 
216
                if(line == None):
 
217
                    curses.beep()
 
218
                    line = ""
 
219
                    cur_histcounter = cur_histcounter - 1
 
220
                win2.addstr(2, 2, line)
 
221
                win2.refresh() #refreshen
 
222
            elif char == curses.KEY_NPAGE: #bild auf
 
223
                try:
 
224
                    page += 1
 
225
                except NameError:
 
226
                    page = i-maxy+4
 
227
                    page += 1
 
228
                line_start = page
 
229
                if line_start > i-maxy+4:
 
230
                    line_start = i-maxy+4
 
231
                    curses.beep()
 
232
                pad.refresh(line_start, col_start, 1, 1, maxy-2, maxx-2)
 
233
            elif char == curses.KEY_PPAGE: #bild ab
 
234
                try:
 
235
                    page -= 1
 
236
                except NameError:
 
237
                    page = i-maxy+4
 
238
                    page -= 1
 
239
                line_start = page
 
240
                if line_start < 0:
 
241
                    line_start = 0
 
242
                    curses.beep()
 
243
                pad.refresh(line_start, col_start, 1, 1, maxy-2, maxx-2)
 
244
            elif char == curses.KEY_END:
 
245
                del page
 
246
                line_start = i-maxy+4
 
247
                pad.refresh(line_start, col_start, 1, 1, maxy-2, maxx-2)
 
248
            elif char == 10: #enter
 
249
                histcounter = histcounter +1
 
250
                cur_histcounter = histcounter
 
251
                readline.add_history(line)
 
252
                if(line == "help"):#hilfe ausgeben
 
253
                    pad.addstr(i, 2, _("+--------------------------------------------------+"))
 
254
                    i= i+1
 
255
                    pad.addstr(i, 2, _("|                    pyTerm help                   |"))
 
256
                    i= i+1
 
257
                    pad.addstr(i, 2, _("|                 Built-in Commands:               |"))
 
258
                    i= i+1
 
259
                    pad.addstr(i, 2, _("|                 exit: Exit pyTerm                |"))
 
260
                    i= i+1
 
261
                    pad.addstr(i, 2, _("|                 reset: Reset RP6                 |"))
 
262
                    i= i+1
 
263
                    pad.addstr(i, 2, _("|            start: Start Program on RP6           |"))
 
264
                    i= i+1
 
265
                    pad.addstr(i, 2, _("|                       Keys:                      |"))
 
266
                    i= i+1
 
267
                    pad.addstr(i, 2, _("|             PageUp: Scroll up in Term            |"))
 
268
                    i= i+1
 
269
                    pad.addstr(i, 2, _("|           PageDown: Scroll down in Term          |"))
 
270
                    i= i+1
 
271
                    pad.addstr(i, 2, _("|                End: stop scrolling               |"))
 
272
                    i= i+1
 
273
                    pad.addstr(i, 2, _("+--------------------------------------------------+"))
 
274
                elif line == "exit": #ende
 
275
                    exit = 1 #endlosschleife verlassen
 
276
                    os.kill(pid, signal.SIGTERM) #child (robbytopipe) killen
 
277
                elif line == "reset": #robby-reset
 
278
                    ser.setRTS(1) #rts ein
 
279
                    time.sleep(0.1) #kurz warten
 
280
                    ser.setRTS(0) #rts aus
 
281
                elif line == "start":
 
282
                    try:
 
283
                        ser.write(bytes('s', encoding='ascii'))#
 
284
                        ser.write(bytes("\x0A", encoding='ascii'))
 
285
                    except:#python 2.6 fallback
 
286
                        ser.write('s')
 
287
                        ser.write("\x0A")
 
288
                else:
 
289
                    pad.addstr(i, 2, "# "+line) #befehl auf pad schreiben
 
290
                    try:
 
291
                        ser.write(bytes(line, encoding='ascii'))#
 
292
                        ser.write(bytes("\x0A", encoding='ascii'))
 
293
                    except:#python 2.6 fallback
 
294
                        ser.write(line)
 
295
                        ser.write("\x0A")
 
296
                line_start = i-maxy+4
 
297
                pad.refresh(line_start, col_start, 1, 1, maxy-2, maxx-2)
 
298
                i = i+1
 
299
                win2.clear()
 
300
                win2.box()
 
301
                win2.addstr(1, 2, _("Please Enter your command (help for a list of built-in commands): "))
 
302
                win2.addstr(2, 2, "")
 
303
                win2.refresh()
 
304
                line = ""
 
305
            elif char > 31 and char < 127:
 
306
                win2.addch(char)
 
307
                line += chr(char)
 
308
            win2.refresh()
 
309
    curses.nocbreak()
 
310
    stdscr.keypad(0)
 
311
    curses.echo()
 
312
    curses.endwin()
 
313
    readline.write_history_file(histpath)
 
314
 
 
315
if not os.path.exists(pipe_name):
 
316
    os.mkfifo(pipe_name)
 
317
pid = os.fork()
 
318
if pid != 0:
 
319
    termtorobby(pid)
 
320
else:
 
321
    robbytopipe()