├── requirements.txt ├── README.md ├── LICENSE └── baudrate.py /requirements.txt: -------------------------------------------------------------------------------- 1 | pySerial 2 | getch -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Baudrate Python 3 - fork of baudrate 2 | 3 | ```bash 4 | git clone https://github.com/sickcodes/python3-baudrate 5 | cd python3-baudrate 6 | pipenv run pip install -r requirements.txt 7 | pipenv run sudo python baudrate.py -a 8 | 9 | # or without pipenv 10 | # pip install -r requirements.txt 11 | # sudo python baudrate.py 12 | ``` 13 | 14 | Forked and cherry-picked @Loris1123 commit because he deleted his repo. 15 | 16 | Added requirements.txt 17 | 18 | See PR: https://github.com/devttys0/baudrate/pull/4#commits-pushed-0eb5f36 19 | 20 | 21 | # Credits 22 | 23 | Original author Craig Heffner @devttys0: https://github.com/devttys0/baudrate 24 | 25 | Upgraded to Python3 by @Loris1123: https://github.com/Loris1123 26 | 27 | Modernized by Sick.Codes @sickcodes : https://github.com/sickcodes 28 | 29 | # Follow for Updates 30 | 31 | https://twitter.com/sickcodes 32 | 33 | https://sick.codes 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 devttys0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Copyright (c) 2020 sickcodes 24 | 25 | Permission is hereby granted, free of charge, to any person obtaining a copy 26 | of this software and associated documentation files (the "Software"), to deal 27 | in the Software without restriction, including without limitation the rights 28 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 29 | copies of the Software, and to permit persons to whom the Software is 30 | furnished to do so, subject to the following conditions: 31 | 32 | The above copyright notice and this permission notice shall be included in all 33 | copies or substantial portions of the Software. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 36 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 37 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 38 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 39 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 40 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 41 | SOFTWARE. 42 | 43 | -------------------------------------------------------------------------------- /baudrate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # License: MIT 3 | # Authors: 4 | # Craig Heffner @devttys0 https://github.com/devttys0 5 | # @Loris1123 https://github.com/Loris1123 6 | # Sick.Codes @sickcodes https://github.com/sickcodes 7 | # Usage: 8 | # pip install -r requirements.txt 9 | # sudo python baudrate.py /dev/ttyUSB0 10 | 11 | import sys 12 | import time 13 | import serial 14 | from threading import Thread 15 | import tty 16 | import termios 17 | import subprocess 18 | from getopt import getopt as GetOpt, GetoptError 19 | import getch 20 | 21 | class RawInput: 22 | """Gets a single character from standard input. Does not echo to the screen.""" 23 | def __init__(self): 24 | try: 25 | self.impl = RawInputWindows() 26 | except ImportError: 27 | self.impl = RawInputUnix() 28 | 29 | def __call__(self): return self.impl() 30 | 31 | 32 | class RawInputUnix: 33 | def __call__(self): 34 | fd = sys.stdin.fileno() 35 | old_settings = termios.tcgetattr(fd) 36 | try: 37 | tty.setraw(sys.stdin.fileno()) 38 | ch = sys.stdin.read(1) 39 | finally: 40 | termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) 41 | return ch 42 | 43 | 44 | class RawInputWindows: 45 | def __call__(self): 46 | return getch.getch() 47 | 48 | class Baudrate: 49 | 50 | VERSION = '3.0' 51 | READ_TIMEOUT = 5 52 | BAUDRATES = [ 53 | "110", 54 | "300", 55 | "600", 56 | "1200", 57 | "1800", 58 | "2400", 59 | "3600", 60 | "4800", 61 | "7200", 62 | "9600", 63 | "14400", 64 | "19200", 65 | "28800", 66 | "31250", 67 | "38400", 68 | "57600", 69 | "76800", 70 | "115200", 71 | "128000", 72 | "153600", 73 | "230400", 74 | "250000", 75 | "256000", 76 | "307200", 77 | "345600", 78 | "460800", 79 | "500000", 80 | "512000", 81 | "921600", 82 | "1024000", 83 | "2000000", 84 | "2500000", 85 | "3000000", 86 | "3686400", 87 | ] 88 | 89 | UPKEYS = ['u', 'U', 'A'] 90 | DOWNKEYS = ['d', 'D', 'B'] 91 | 92 | MIN_CHAR_COUNT = 25 93 | WHITESPACE = [' ', '\t', '\r', '\n'] 94 | PUNCTUATION = ['.', ',', ':', ';', '?', '!'] 95 | VOWELS = ['a', 'A', 'e', 'E', 'i', 'I', 'o', 'O', 'u', 'U'] 96 | 97 | def __init__(self, port=None, threshold=MIN_CHAR_COUNT, timeout=READ_TIMEOUT, name=None, auto=True, verbose=False): 98 | self.port = port 99 | self.threshold = threshold 100 | self.timeout = timeout 101 | self.name = name 102 | self.auto_detect = auto 103 | self.verbose = verbose 104 | self.index = len(self.BAUDRATES) - 1 105 | self.valid_characters = [] 106 | self.ctlc = False 107 | self.thread = None 108 | 109 | self._gen_char_list() 110 | 111 | def _gen_char_list(self): 112 | c = ' ' 113 | 114 | while c <= '~': 115 | self.valid_characters.append(c) 116 | c = chr(ord(c) + 1) 117 | 118 | for c in self.WHITESPACE: 119 | if c not in self.valid_characters: 120 | self.valid_characters.append(c) 121 | 122 | def _print(self, data): 123 | if self.verbose: 124 | sys.stderr.buffer.write(data) 125 | sys.stderr.buffer.flush() 126 | 127 | def Open(self): 128 | pass 129 | self.serial = serial.Serial(self.port, timeout=self.timeout) 130 | self.NextBaudrate(0) 131 | 132 | def NextBaudrate(self, updn): 133 | 134 | self.index += updn 135 | 136 | if self.index >= len(self.BAUDRATES): 137 | self.index = 0 138 | elif self.index < 0: 139 | self.index = len(self.BAUDRATES) - 1 140 | 141 | sys.stderr.write('\n\n@@@@@@@@@@@@@@@@@@@@@ Baudrate: %s @@@@@@@@@@@@@@@@@@@@@\n\n' % self.BAUDRATES[self.index]) 142 | 143 | self.serial.flush() 144 | self.serial.baudrate = self.BAUDRATES[self.index] 145 | self.serial.flush() 146 | 147 | def Detect(self): 148 | count = 0 149 | whitespace = 0 150 | punctuation = 0 151 | vowels = 0 152 | start_time = 0 153 | timed_out = False 154 | clear_counters = False 155 | 156 | if not self.auto_detect: 157 | self.thread = Thread(None, self.HandleKeypress, None, (self, 1)) 158 | self.thread.start() 159 | 160 | while True: 161 | if start_time == 0: 162 | start_time = time.time() 163 | 164 | byte = self.serial.read(1) 165 | 166 | if byte: 167 | if self.auto_detect and byte in self.valid_characters: 168 | if byte in self.WHITESPACE: 169 | whitespace += 1 170 | elif byte in self.PUNCTUATION: 171 | punctuation += 1 172 | elif byte in self.VOWELS: 173 | vowels += 1 174 | 175 | count += 1 176 | else: 177 | clear_counters = True 178 | 179 | self._print(byte) 180 | 181 | if count >= self.threshold and whitespace > 0 and punctuation > 0 and vowels > 0: 182 | break 183 | elif (time.time() - start_time) >= self.timeout: 184 | timed_out = True 185 | else: 186 | timed_out = True 187 | 188 | if timed_out and self.auto_detect: 189 | start_time = 0 190 | self.NextBaudrate(-1) 191 | clear_counters = True 192 | timed_out = False 193 | 194 | if clear_counters: 195 | whitespace = 0 196 | punctuation = 0 197 | vowels = 0 198 | count = 0 199 | clear_counters = False 200 | 201 | if self.ctlc: 202 | break 203 | 204 | return self.BAUDRATES[self.index] 205 | 206 | def HandleKeypress(self, *args): 207 | userinput = RawInput() 208 | while not self.ctlc: 209 | c = userinput() 210 | if c in self.UPKEYS: 211 | self.NextBaudrate(1) 212 | elif c in self.DOWNKEYS: 213 | self.NextBaudrate(-1) 214 | elif c == '\x03': 215 | self.ctlc = True 216 | 217 | def MinicomConfig(self, name=None): 218 | success = True 219 | 220 | if name is None: 221 | name = self.name 222 | 223 | config = "########################################################################\n" 224 | config += "# Minicom configuration file - use \"minicom -s\" to change parameters.\n" 225 | config += "pu port %s\n" % self.port 226 | config += "pu baudrate %s\n" % self.BAUDRATES[self.index] 227 | config += "pu bits 8\n" 228 | config += "pu parity N\n" 229 | config += "pu stopbits 1\n" 230 | config += "pu rtscts No\n" 231 | config += "########################################################################\n" 232 | 233 | if name is not None and name: 234 | try: 235 | open("/etc/minicom/minirc.%s" % name, "w").write(config) 236 | except Exception as e: 237 | print("Error saving minicom config file:", str(e)) 238 | success = False 239 | 240 | return (success, config) 241 | 242 | def Close(self): 243 | self.ctlc = True 244 | self.serial.close() 245 | 246 | 247 | 248 | if __name__ == '__main__': 249 | 250 | 251 | def usage(): 252 | baud = Baudrate() 253 | 254 | print("Baudrate v%s" % baud.VERSION) 255 | print("Craig Heffner, http://www.devttys0.com") 256 | print("@Loris1123, https://github.com/Loris1123") 257 | print("Sick.Codes, https://sick.codes") 258 | print("") 259 | print("Usage: %s [OPTIONS]" % sys.argv[0]) 260 | print("") 261 | print("\t-p Specify the serial port to use [/dev/ttyUSB0]") 262 | print("\t-t Set the timeout period used when switching baudrates in auto detect mode [%d]" % baud.READ_TIMEOUT) 263 | print("\t-c Set the minimum ASCII character threshold used during auto detect mode [%d]" % baud.MIN_CHAR_COUNT) 264 | print("\t-n Save the resulting serial configuration as and automatically invoke minicom (implies -a)") 265 | print("\t-a Enable auto detect mode") 266 | print("\t-b Display supported baud rates and exit") 267 | print("\t-q Do not display data read from the serial port") 268 | print("\t-h Display help") 269 | print("") 270 | sys.exit(1) 271 | 272 | def main(): 273 | display = False 274 | verbose = True 275 | auto = False 276 | run = False 277 | threshold = 25 278 | timeout = 1 279 | name = None 280 | port = '/dev/ttyUSB0' 281 | 282 | try: 283 | (opts, args) = GetOpt(sys.argv[1:], 'p:t:c:n:abqh') 284 | except GetoptError as e: 285 | print(e) 286 | usage() 287 | 288 | for opt, arg in opts: 289 | if opt == '-t': 290 | timeout = int(arg) 291 | elif opt == '-c': 292 | threshold = int(arg) 293 | elif opt == '-p': 294 | port = arg 295 | elif opt == '-n': 296 | name = arg 297 | auto = True 298 | run = True 299 | elif opt == '-a': 300 | auto = True 301 | elif opt == '-b': 302 | display = True 303 | elif opt == '-q': 304 | verbose = False 305 | else: 306 | usage() 307 | 308 | baud = Baudrate(port, threshold=threshold, timeout=timeout, name=name, verbose=verbose, auto=auto) 309 | 310 | if display: 311 | print("") 312 | for rate in baud.BAUDRATES: 313 | print("\t{}".format(rate)) 314 | print("") 315 | else: 316 | print("") 317 | print("Starting baudrate detection on %s, turn on your serial device now." % port) 318 | print("Press Up/Down to switch baudrates.") 319 | print("Press Ctl+C to quit.") 320 | print("") 321 | 322 | baud.Open() 323 | 324 | try: 325 | rate = baud.Detect() 326 | print("\nDetected baudrate: {}".format(rate)) 327 | 328 | if name is None: 329 | print("\nSave minicom configuration as: ", end=" ") 330 | name = sys.stdin.readline().strip() 331 | print("") 332 | 333 | (ok, config) = baud.MinicomConfig(name) 334 | if name and name is not None: 335 | if ok: 336 | if not run: 337 | print("Configuration saved. Run minicom now [n/Y]? ", end=" ") 338 | yn = sys.stdin.readline().strip() 339 | print("") 340 | if yn == "" or yn.lower().startswith('y'): 341 | run = True 342 | 343 | if run: 344 | subprocess.call(["minicom", name]) 345 | else: 346 | print(config) 347 | else: 348 | print(config) 349 | except KeyboardInterrupt: 350 | pass 351 | 352 | baud.Close() 353 | 354 | main() 355 | 356 | --------------------------------------------------------------------------------