Newer
Older
DirtyScripts / baudrate.py
root on 25 Mar 2020 9 KB useful script
  1. #!/usr/bin/env python
  2.  
  3. import sys
  4. import time
  5. import serial
  6. from threading import Thread
  7.  
  8. class RawInput:
  9. """Gets a single character from standard input. Does not echo to the screen."""
  10. def __init__(self):
  11. try:
  12. self.impl = RawInputWindows()
  13. except ImportError:
  14. self.impl = RawInputUnix()
  15.  
  16. def __call__(self): return self.impl()
  17.  
  18.  
  19. class RawInputUnix:
  20. def __init__(self):
  21. import tty, sys
  22.  
  23. def __call__(self):
  24. import sys, tty, termios
  25. fd = sys.stdin.fileno()
  26. old_settings = termios.tcgetattr(fd)
  27. try:
  28. tty.setraw(sys.stdin.fileno())
  29. ch = sys.stdin.read(1)
  30. finally:
  31. termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
  32. return ch
  33.  
  34.  
  35. class RawInputWindows:
  36. def __init__(self):
  37. import msvcrt
  38.  
  39. def __call__(self):
  40. import msvcrt
  41. return msvcrt.getch()
  42.  
  43. class Baudrate:
  44.  
  45. VERSION = '1.0'
  46. READ_TIMEOUT = 5
  47. BAUDRATES = [
  48. # "1200",
  49. # "1800",
  50. # "2400",
  51. # "4800",
  52. "9600",
  53. "38400",
  54. "19200",
  55. "57600",
  56. "115200",
  57. ]
  58.  
  59. UPKEYS = ['u', 'U', 'A']
  60. DOWNKEYS = ['d', 'D', 'B']
  61.  
  62. MIN_CHAR_COUNT = 25
  63. WHITESPACE = [' ', '\t', '\r', '\n']
  64. PUNCTUATION = ['.', ',', ':', ';', '?', '!']
  65. VOWELS = ['a', 'A', 'e', 'E', 'i', 'I', 'o', 'O', 'u', 'U']
  66.  
  67. def __init__(self, port=None, threshold=MIN_CHAR_COUNT, timeout=READ_TIMEOUT, name=None, auto=True, verbose=False):
  68. self.port = port
  69. self.threshold = threshold
  70. self.timeout = timeout
  71. self.name = name
  72. self.auto_detect = auto
  73. self.verbose = verbose
  74. self.index = len(self.BAUDRATES) - 1
  75. self.valid_characters = []
  76. self.ctlc = False
  77. self.thread = None
  78.  
  79. self._gen_char_list()
  80.  
  81. def _gen_char_list(self):
  82. c = ' '
  83.  
  84. while c <= '~':
  85. self.valid_characters.append(c)
  86. c = chr(ord(c) + 1)
  87.  
  88. for c in self.WHITESPACE:
  89. if c not in self.valid_characters:
  90. self.valid_characters.append(c)
  91.  
  92. def _print(self, data):
  93. if self.verbose:
  94. sys.stderr.write(data)
  95.  
  96. def Open(self):
  97. self.serial = serial.Serial(self.port, timeout=self.timeout)
  98. self.NextBaudrate(0)
  99.  
  100. def NextBaudrate(self, updn):
  101.  
  102. self.index += updn
  103.  
  104. if self.index >= len(self.BAUDRATES):
  105. self.index = 0
  106. elif self.index < 0:
  107. self.index = len(self.BAUDRATES) - 1
  108.  
  109. sys.stderr.write('\n\n@@@@@@@@@@@@@@@@@@@@@ Baudrate: %s @@@@@@@@@@@@@@@@@@@@@\n\n' % self.BAUDRATES[self.index])
  110.  
  111. self.serial.flush()
  112. self.serial.baudrate = self.BAUDRATES[self.index]
  113. self.serial.flush()
  114.  
  115. def Detect(self):
  116. count = 0
  117. whitespace = 0
  118. punctuation = 0
  119. vowels = 0
  120. start_time = 0
  121. timed_out = False
  122. clear_counters = False
  123.  
  124. if not self.auto_detect:
  125. self.thread = Thread(None, self.HandleKeypress, None, (self, 1))
  126. self.thread.start()
  127.  
  128. while True:
  129. if start_time == 0:
  130. start_time = time.time()
  131.  
  132. byte = self.serial.read(1)
  133.  
  134. if byte:
  135. if self.auto_detect and byte in self.valid_characters:
  136. if byte in self.WHITESPACE:
  137. whitespace += 1
  138. elif byte in self.PUNCTUATION:
  139. punctuation += 1
  140. elif byte in self.VOWELS:
  141. vowels += 1
  142.  
  143. count += 1
  144. else:
  145. clear_counters = True
  146.  
  147. self._print(byte)
  148.  
  149. if count >= self.threshold and whitespace > 0 and punctuation > 0 and vowels > 0:
  150. break
  151. elif (time.time() - start_time) >= self.timeout:
  152. timed_out = True
  153. else:
  154. timed_out = True
  155.  
  156. if timed_out and self.auto_detect:
  157. start_time = 0
  158. self.NextBaudrate(-1)
  159. clear_counters = True
  160. timed_out = False
  161.  
  162. if clear_counters:
  163. whitespace = 0
  164. punctuation = 0
  165. vowels = 0
  166. count = 0
  167. clear_counters = False
  168.  
  169. if self.ctlc:
  170. break
  171.  
  172. self._print("\n")
  173. return self.BAUDRATES[self.index]
  174.  
  175. def HandleKeypress(self, *args):
  176. userinput = RawInput()
  177.  
  178. while not self.ctlc:
  179. c = userinput()
  180. if c in self.UPKEYS:
  181. self.NextBaudrate(1)
  182. elif c in self.DOWNKEYS:
  183. self.NextBaudrate(-1)
  184. elif c == '\x03':
  185. self.ctlc = True
  186.  
  187. def MinicomConfig(self, name=None):
  188. success = True
  189.  
  190. if name is None:
  191. name = self.name
  192.  
  193. config = "########################################################################\n"
  194. config += "# Minicom configuration file - use \"minicom -s\" to change parameters.\n"
  195. config += "pu port %s\n" % self.port
  196. config += "pu baudrate %s\n" % self.BAUDRATES[self.index]
  197. config += "pu bits 8\n"
  198. config += "pu parity N\n"
  199. config += "pu stopbits 1\n"
  200. config += "pu rtscts No\n"
  201. config += "########################################################################\n"
  202.  
  203. if name is not None and name:
  204. try:
  205. open("/etc/minicom/minirc.%s" % name, "w").write(config)
  206. except Exception, e:
  207. print "Error saving minicom config file:", str(e)
  208. success = False
  209.  
  210. return (success, config)
  211.  
  212. def Close(self):
  213. self.ctlc = True
  214. self.serial.close()
  215.  
  216.  
  217.  
  218. if __name__ == '__main__':
  219.  
  220. import subprocess
  221. from getopt import getopt as GetOpt, GetoptError
  222.  
  223. def usage():
  224. baud = Baudrate()
  225.  
  226. print ""
  227. print "Baudrate v%s" % baud.VERSION
  228. print "Craig Heffner, http://www.devttys0.com"
  229. print ""
  230. print "Usage: %s [OPTIONS]" % sys.argv[0]
  231. print ""
  232. print "\t-p <serial port> Specify the serial port to use [/dev/ttyUSB0]"
  233. print "\t-t <seconds> Set the timeout period used when switching baudrates in auto detect mode [%d]" % baud.READ_TIMEOUT
  234. print "\t-c <num> Set the minimum ASCII character threshold used during auto detect mode [%d]" % baud.MIN_CHAR_COUNT
  235. print "\t-n <name> Save the resulting serial configuration as <name> and automatically invoke minicom (implies -a)"
  236. print "\t-a Enable auto detect mode"
  237. print "\t-b Display supported baud rates and exit"
  238. print "\t-q Do not display data read from the serial port"
  239. print "\t-h Display help"
  240. print ""
  241. sys.exit(1)
  242.  
  243. def main():
  244. display = False
  245. verbose = True
  246. auto = False
  247. run = False
  248. threshold = 25
  249. timeout = 5
  250. name = None
  251. port = '/dev/ttyUSB0'
  252.  
  253. try:
  254. (opts, args) = GetOpt(sys.argv[1:], 'p:t:c:n:abqh')
  255. except GetoptError, e:
  256. print e
  257. usage()
  258.  
  259. for opt, arg in opts:
  260. if opt == '-t':
  261. timeout = int(arg)
  262. elif opt == '-c':
  263. threshold = int(arg)
  264. elif opt == '-p':
  265. port = arg
  266. elif opt == '-n':
  267. name = arg
  268. auto = True
  269. run = True
  270. elif opt == '-a':
  271. auto = True
  272. elif opt == '-b':
  273. display = True
  274. elif opt == '-q':
  275. verbose = False
  276. else:
  277. usage()
  278.  
  279. baud = Baudrate(port, threshold=threshold, timeout=timeout, name=name, verbose=verbose, auto=auto)
  280.  
  281. if display:
  282. print ""
  283. for rate in baud.BAUDRATES:
  284. print "\t%s" % rate
  285. print ""
  286. else:
  287. print ""
  288. print "Starting baudrate detection on %s, turn on your serial device now." % port
  289. print "Press Ctl+C to quit."
  290. print ""
  291.  
  292. baud.Open()
  293.  
  294. try:
  295. rate = baud.Detect()
  296. print "\nDetected baudrate: %s" % rate
  297.  
  298. if name is None:
  299. print "\nSave minicom configuration as: ",
  300. name = sys.stdin.readline().strip()
  301. print ""
  302.  
  303. (ok, config) = baud.MinicomConfig(name)
  304. if name and name is not None:
  305. if ok:
  306. if not run:
  307. print "Configuration saved. Run minicom now [n/Y]? ",
  308. yn = sys.stdin.readline().strip()
  309. print ""
  310. if yn == "" or yn.lower().startswith('y'):
  311. run = True
  312.  
  313. if run:
  314. subprocess.call(["minicom", name])
  315. else:
  316. print config
  317. else:
  318. print config
  319. except KeyboardInterrupt:
  320. pass
  321.  
  322. baud.Close()
  323.  
  324. main()
Buy Me A Coffee