Skip to content

Commit e303abd

Browse files
committed
MPyTerm, added command mode line edit
Added BME280 i2c example
1 parent d40831b commit e303abd

File tree

2 files changed

+449
-40
lines changed

2 files changed

+449
-40
lines changed

k210-freertos/MPyTerm.py

Lines changed: 189 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import argparse
1010
import binascii
1111
import re
12+
import shutil
1213
from threading import Thread
1314
from datetime import datetime
1415
try:
@@ -17,18 +18,53 @@
1718
print("\033[1;31mPySerial must be installed, run \033[1;34m`pip3 install pyserial`\033[0m\r\n")
1819
sys.exit(1)
1920

21+
KEY_NONE = 0x00
22+
KEY_LEFT = 0x1f
23+
KEY_RIGHT = 0x1e
24+
KEY_HOME = 0x10
25+
KEY_END = 0x03
26+
KEY_QUIT = 0x11
27+
KEY_ENTER = 0x0a
28+
KEY_BACKSPACE = 0x08
29+
KEY_DELETE = 0x7f
30+
KEY_TAB = 0x09
31+
KEY_DUP = 0x04
32+
2033
#============
2134
class PyTerm:
2235

36+
KEYMAP = { ## Gets lengthy
37+
"\x1b[D" : KEY_LEFT,
38+
"\x1b[C" : KEY_RIGHT,
39+
"\x1b[H" : KEY_HOME, ## in Linux Terminal
40+
"\x1bOH" : KEY_HOME, ## Picocom, Minicom
41+
"\x1b[1~": KEY_HOME, ## Putty
42+
"\x1b[F" : KEY_END, ## Linux Terminal
43+
"\x1bOF" : KEY_END, ## Picocom, Minicom
44+
"\x1b[4~": KEY_END, ## Putty
45+
"\x03" : KEY_DUP, ## Ctrl-C
46+
"\r" : KEY_ENTER,
47+
"\x7f" : KEY_BACKSPACE, ## Ctrl-? (127)
48+
"\x1b[3~": KEY_DELETE,
49+
"\x11" : KEY_QUIT, ## Ctrl-Q
50+
"\x1bq" : KEY_QUIT, ## Alt-Q
51+
"\n" : KEY_ENTER,
52+
"\x04" : KEY_DUP, ## Ctrl-D
53+
"\x09" : KEY_TAB,
54+
}
55+
2356
#-----------------------------------------------------------------
2457
def __init__(self, baudrate=115200, device='/dev/ttyUSB0', rst=0):
2558
self.DEVICE = device
2659
self.BAUDRATE = baudrate
2760
self.ESCAPECHAR = "\033"
28-
self.VERSION = "5.1.2"
61+
self.VERSION = "5.1.3"
2962
self.ShutdownReceiver = False
3063
self.ReceiverToStdout = True
3164
self.DefaultTimeout = 0.1
65+
self.width = 80
66+
self.height = 80
67+
self.width, self.height = shutil.get_terminal_size()
3268

3369
print("\n\033[1;31m--[ \033[1;34mMicroPython terminal \033[1;31m ver. \033[1;34m" + self.VERSION + "\033[1;31m ]-- \033[0m")
3470
print("\033[1;31m--[ \033[1;34mPress ESC twice for command mode\033[1;31m ]-- \033[0m\n")
@@ -49,6 +85,9 @@ def __init__(self, baudrate=115200, device='/dev/ttyUSB0', rst=0):
4985
self.uart.dtr = False
5086
time.sleep(0.1)
5187
self.uart.dtr = True
88+
else:
89+
self.uart.write(b'\r\n')
90+
5291
except Exception as e:
5392
raise Exception("\033[1;31mAccessing \033[1;37m" + self.DEVICE + " \033[1;31mfailed\r\n\033[1;37mPyTerm exit\033[0m\r\n")
5493

@@ -77,6 +116,84 @@ def __init__(self, baudrate=115200, device='/dev/ttyUSB0', rst=0):
77116
termios.tcsetattr(self.stdinfd, termios.TCSADRAIN, self.oldstdinsettings)
78117
self.uart.close()
79118

119+
#----------------------
120+
def clear_to_eol(self):
121+
sys.stdout.write("\x1b[0K")
122+
sys.stdout.flush()
123+
124+
#-------------------
125+
def get_input(self): ## read from interface/keyboard one byte each and match against function keys
126+
while True:
127+
in_buffer = sys.stdin.read(1)
128+
if in_buffer == '\x1b': ## starting with ESC, must be fct
129+
while True:
130+
in_buffer += sys.stdin.read(1)
131+
c = in_buffer[-1]
132+
if c == '~' or (c.isalpha() and c != 'O'):
133+
break
134+
if in_buffer in self.KEYMAP:
135+
c = self.KEYMAP[in_buffer]
136+
return c, None
137+
elif ord(in_buffer[0]) >= 32:
138+
return KEY_NONE, in_buffer
139+
140+
# Line editor
141+
#------------------------------------------------
142+
def line_edit(self, prompt, prompt_len, default):
143+
# Write a message and move cursor back
144+
push_msg = lambda msg: sys.stdout.write(msg + "\b" * len(msg))
145+
sys.stdout.write(prompt)
146+
sys.stdout.write(default)
147+
sys.stdout.flush()
148+
self.clear_to_eol()
149+
res = default
150+
pos = len(res)
151+
while True:
152+
key, char = self.get_input() ## Get Char of Fct.
153+
if key == KEY_NONE: ## char to be inserted
154+
if (prompt_len + len(res)) < (self.width - 2):
155+
res = res[:pos] + char + res[pos:]
156+
sys.stdout.write(res[pos])
157+
sys.stdout.flush()
158+
pos += len(char)
159+
push_msg(res[pos:]) ## update tail
160+
sys.stdout.flush()
161+
elif key in (KEY_ENTER, KEY_TAB): ## Finis
162+
return res
163+
elif key in (KEY_QUIT, KEY_DUP): ## Abort
164+
return None
165+
elif key == KEY_LEFT:
166+
if pos > 0:
167+
sys.stdout.write("\b")
168+
sys.stdout.flush()
169+
pos -= 1
170+
elif key == KEY_RIGHT:
171+
if pos < len(res):
172+
sys.stdout.write(res[pos])
173+
sys.stdout.flush()
174+
pos += 1
175+
elif key == KEY_HOME:
176+
sys.stdout.write("\b" * pos)
177+
sys.stdout.flush()
178+
pos = 0
179+
elif key == KEY_END:
180+
sys.stdout.write(res[pos:])
181+
sys.stdout.flush()
182+
pos = len(res)
183+
elif key == KEY_DELETE: ## Delete
184+
if pos < len(res):
185+
res = res[:pos] + res[pos+1:]
186+
push_msg(res[pos:] + ' ') ## update tail
187+
sys.stdout.flush()
188+
elif key == KEY_BACKSPACE: ## Backspace
189+
if pos > 0:
190+
res = res[:pos-1] + res[pos:]
191+
sys.stdout.write("\b")
192+
sys.stdout.flush()
193+
pos -= 1
194+
push_msg(res[pos:] + ' ') ## update tail
195+
sys.stdout.flush()
196+
80197
#-----------------------------------------
81198
def ReceiveData(self, uart, binary=False):
82199
data = ""
@@ -406,26 +523,6 @@ def ReadDirFromRemote(self, remote_dir, short=True):
406523
pass
407524
return dirlist
408525

409-
#---------------------
410-
def ReadCommand(self):
411-
char = ""
412-
command = ""
413-
414-
while True:
415-
char = sys.stdin.read(1)
416-
if char == "\r":
417-
break
418-
elif char == self.ESCAPECHAR:
419-
if len(command) == 0:
420-
command = self.ESCAPECHAR
421-
break
422-
else:
423-
sys.stdout.write(char)
424-
sys.stdout.flush()
425-
command += char
426-
427-
return command
428-
429526
#----------------------
430527
def Get2ndEscape(self):
431528
char = sys.stdin.read(1)
@@ -447,15 +544,17 @@ def HandleUnbufferedUserInput(self):
447544

448545
if char == self.ESCAPECHAR:
449546
if self.Get2ndEscape():
450-
print("\r\n\033[1;31m--[\033[1;34mmpTerm command: \033[0m", end="")
451-
command = self.ReadCommand()
547+
prompt = "\033[1;31m--[\033[1;34mmpTerm command: \033[0m"
548+
print("\r\n")
549+
#command = self.ReadCommand()
550+
command = self.line_edit(prompt, 19, '')
452551

453-
if command == self.ESCAPECHAR:
454-
sys.stdout.write("\r\n")
455-
sys.stdout.flush()
456-
self.uart.write(self.ESCAPECHAR.encode("utf-8"))
552+
if command is None:
553+
#sys.stdout.write("\r\n")
554+
#sys.stdout.flush()
555+
print("\r{}\033[1;37maborted\033[0m\033[0K".format(prompt), end="\r\n")
457556

458-
if command == "exit":
557+
elif command == "exit":
459558
print("\r\n\033[1;34m Exit PyTerm \033[1;31m]--\033[0m\r\n", end="")
460559
break
461560

@@ -588,6 +687,52 @@ def HandleUnbufferedUserInput(self):
588687
except Exception as e:
589688
print("\r\nError", e, end="\r\n")
590689

690+
elif command[0:8] == "lslocal ":
691+
try:
692+
cmd = re.sub(' +', ' ', command.strip()).split(' ')
693+
if (len(cmd) == 2) or (len(cmd) == 3):
694+
short_list = False
695+
if (len(cmd) == 3):
696+
if cmd[2] == "short":
697+
short_list = True
698+
rdir = cmd[1]
699+
lpath = os.path.abspath(rdir)
700+
dirlst = os.listdir(rdir)
701+
702+
if len(dirlst) > 0:
703+
sys.stdout.write("\r\n\r\nList of directory '{}':\r\n".format(lpath))
704+
sys.stdout.write("{}\r\n".format("".rjust(21+len(lpath), '-')))
705+
if short_list is False:
706+
dirlist = []
707+
for f in dirlst:
708+
file_path = os.path.abspath(lpath + "/" + f)
709+
st = os.stat(file_path)
710+
dirlist.append((f, (st[0] & 0x8000) == 0, st[6], st[8]))
711+
712+
dirlist.sort(key=lambda x: (not x[1], x[0].lower()))
713+
714+
max_name_len = 0
715+
max_size_len = 0
716+
for f in dirlist:
717+
if len(f[0]) > max_name_len:
718+
max_name_len = len(f[0])
719+
if len(str(f[2])) > max_size_len:
720+
max_size_len = len(str(f[2]))
721+
max_name_len += 1
722+
max_size_len += 1
723+
for f in dirlist:
724+
print("{} {} {} {}".format(f[0].rjust(max_name_len), " <dir>" if f[1] else "<file>", str(f[2]).rjust(max_size_len), datetime.utcfromtimestamp(f[3]).strftime('%Y-%m-%d %H:%M:%S')), end="\r\n")
725+
else:
726+
dirlst.sort(key=lambda name: name.lower())
727+
for f in dirlst:
728+
print("{}".format(f), end="\r\n")
729+
else:
730+
print("\r\nNo files to list\r\n{}\r\n".format(dirlist))
731+
else:
732+
print("\r\nWrong command arguments", end="\r\n")
733+
except Exception as e:
734+
print("\r\nError", e, end="\r\n")
735+
591736
elif command[0:9] == "baudrate ":
592737
try:
593738
cmd = re.sub(' +', ' ', command.strip()).split(' ')
@@ -621,20 +766,24 @@ def HandleUnbufferedUserInput(self):
621766
print("Error", end="\r\n")
622767

623768
else:
624-
print(""" \033[1;37munknown command\033[0m, use one of the following commands:\r
625-
\033[1;34m exit \033[0m - exit the terminal\r
626-
\033[1;34m version \033[0m - print version info\r
627-
\033[1;34m synctime \033[0m - synchronize device time to the PC time\r
628-
\033[1;34m baudrate <bdr> \033[0m - set terminal baudrate\r
629-
\033[1;34mset_baudrate <bdr> \033[0m - set device and terminal baudrate\r
630-
\033[1;34m send <lfile> <rfile>\033[0m - send file to device\r
631-
\033[1;34m recv <rfile> <lfile>\033[0m - receive file from device\r
632-
\033[1;34m senddir <ldir> <rdir> \033[0m - send all files from local directory to device's directory\r
633-
\033[1;34m recvdir <rdir> <ldir> \033[0m - receive all files from device's directory to local directory\r
634-
\033[1;34m ls <rdir> [short]\033[0m - list remote directory, if 'short' is given, only file names are printed\r
635-
""")
769+
print("""\r{}\033[1;31munknown command !\033[0m\r\n\033[1;37mAvailable commands:\033[0m\033[0K\r
770+
\033[1;34m exit \033[0m - exit the terminal\r
771+
\033[1;34m version \033[0m - print version info\r
772+
\033[1;34m synctime \033[0m - synchronize device time to the PC time\r
773+
\033[1;34m baudrate \033[0m\033[1;37mbdr \033[0m - set terminal baudrate\r
774+
\033[1;34mset_baudrate \033[0m\033[1;37mbdr \033[0m - set device and terminal baudrate\r
775+
\033[1;34m send \033[0m\033[1;37mlfile rfile\033[0m - send file to device\r
776+
\033[1;34m recv \033[0m\033[1;37mrfile lfile\033[0m - receive file from device\r
777+
\033[1;34m senddir \033[0m\033[1;37mldir rdir \033[0m - send all files from local directory to device's directory\r
778+
\033[1;34m recvdir \033[0m\033[1;37mrdir ldir \033[0m - receive all files from device's directory to local directory\r
779+
\033[1;34m ls \033[0m\033[1;37mrdir [short]\033[0m - list remote directory, if 'short' is given, only file names are printed\r
780+
\033[1;34m lslocal \033[0m\033[1;37mrdir [short]\033[0m - list local directory, if 'short' is given, only file names are printed\r
781+
\033[1;33m Enter \033[0m - accept and execute command\r
782+
\033[1;33m Ctrl-Q \033[0m - aborts command mode\r
783+
""".format(prompt))
636784

637785
print("\033[1;34mback to device \033[1;31m]--\033[0m\r\n", end="")
786+
self.uart.write(b'\r\n')
638787
else:
639788
data = char.encode("utf-8")
640789
self.uart.write(data)

0 commit comments

Comments
 (0)