mysmartusb.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #!/usr/bin/env python3
  2. """
  3. # Copyright (C) 2012-2021 Michael Buesch <m@bues.ch>
  4. #
  5. # Licensed under the Apache License version 2.0
  6. # or the MIT license, at your option.
  7. # SPDX-License-Identifier: Apache-2.0 OR MIT
  8. """
  9. import sys
  10. import getopt
  11. import time
  12. try:
  13. from serial import *
  14. except ImportError:
  15. print("ERROR: pyserial module not available.")
  16. print("On Debian Linux please do: apt-get install python3-serial")
  17. sys.exit(1)
  18. def str2bool(string):
  19. if string.lower() in ("true", "on", "yes"):
  20. return True
  21. if string.lower() in ("false", "off", "no"):
  22. return False
  23. try:
  24. return bool(int(string))
  25. except ValueError as e:
  26. pass
  27. return False
  28. def hexdump(data):
  29. ret = []
  30. for c in data:
  31. ret.append("%02X" % c)
  32. return "".join(ret)
  33. class MySmartUsbError(Exception): pass
  34. class MySmartUsb(object):
  35. PREFIX = b"\xE6\xB5\xBA\xB9\xB2\xB3\xA9"
  36. MODE_PROG = b'p'
  37. MODE_DATA = b'd'
  38. MODE_QUIET = b'q'
  39. def __init__(self, ttyDev, debug=False):
  40. self.debug = debug
  41. self.serial = Serial(ttyDev, 19200, 8, PARITY_NONE, 1)
  42. self.serial.flushInput()
  43. self.serial.flushOutput()
  44. def resetBoard(self):
  45. self.__sendCmd(b'r')
  46. def resetProg(self):
  47. self.__sendCmd(b'R')
  48. def power(self, on):
  49. self.__sendCmd(b'+' if on else b'-')
  50. def setMode(self, mode):
  51. if self.getMode() == mode:
  52. return
  53. self.__sendCmd(mode)
  54. time.sleep(0.5)
  55. if self.getMode() == mode:
  56. return
  57. raise MySmartUsbError("Failed to set mode")
  58. def getMode(self):
  59. return self.__sendCmd(b'i')
  60. def getVersion(self):
  61. b = self.__sendCmd(b'v')
  62. try:
  63. return b.decode('ASCII')
  64. except UnicodeError:
  65. raise MySmartUsbError("Failed to read version string")
  66. def close(self):
  67. self.serial.flush()
  68. self.serial.close()
  69. def __sendCmd(self, cmd):
  70. data = self.PREFIX + cmd
  71. if self.debug:
  72. print("Sending command: " + hexdump(data))
  73. self.serial.write(data)
  74. self.serial.flush()
  75. if cmd == b'R':
  76. return
  77. if cmd == b'v':
  78. time.sleep(0.25)
  79. count = self.serial.inWaiting()
  80. ret = self.serial.read(count)
  81. ret = ret[ret.find(b'\xF7')+1:]
  82. ret = ret[:ret.find(b'\xF7')]
  83. return ret
  84. ret = self.serial.read(5)
  85. while ret[0:2] != b"\xF7\xB1" or ret[3:5] != b"\x0D\x0A":
  86. ret = ret[1:] + self.serial.read(1)
  87. if self.debug:
  88. print("Command returned: " + hexdump(ret))
  89. if cmd != b'i' and ret[2] != ord(cmd):
  90. raise MySmartUsbError(
  91. "Invalid command return: %02X" %\
  92. (ret[2]))
  93. return bytes( (ret[2], ) )
  94. def usage():
  95. print("mysmartusb [OPTIONS] /dev/ttyUSBx")
  96. print("")
  97. print("Options:")
  98. print(" -r|--reset-board Reset the board")
  99. print(" -R|--reset-prog Reset the programmer")
  100. print(" -p|--power 1/0 Turn on board power on/off")
  101. print(" -m|--mode p/d/q Enter progmode/datamode/quietmode")
  102. print(" -V|--getversion Read and display the mysmartusb version")
  103. print("")
  104. print(" -D|--debug Enable debugging")
  105. def main():
  106. actions = []
  107. debug = False
  108. try:
  109. (opts, args) = getopt.getopt(sys.argv[1:],
  110. "hrRp:m:VD",
  111. [ "help", "reset-board", "reset-prog", "prog=",
  112. "mode=", "getversion", "debug", ])
  113. except getopt.GetoptError:
  114. usage()
  115. return 1
  116. for (o, v) in opts:
  117. if o in ("-h", "--help"):
  118. usage()
  119. return 0
  120. if o in ("-r", "--reset-board"):
  121. actions.append( ("reset-board",) )
  122. if o in ("-R", "--reset-prog"):
  123. actions.append( ("reset-prog",) )
  124. if o in ("-p", "--power"):
  125. actions.append( ("power", str2bool(v)) )
  126. if o in ("-m", "--mode"):
  127. if v.lower() == "p":
  128. mode = MySmartUsb.MODE_PROG
  129. elif v.lower() == "d":
  130. mode = MySmartUsb.MODE_DATA
  131. elif v.lower() == "q":
  132. mode = MySmartUsb.MODE_QUIET
  133. else:
  134. print("Invalid mode: " + v)
  135. return 1
  136. actions.append( ("mode", mode) )
  137. if o in ("-V", "--getversion"):
  138. actions.append( ("getversion",) )
  139. if o in ("-D", "--debug"):
  140. debug = True
  141. if len(args) != 1:
  142. usage()
  143. return 1
  144. dev = args[0]
  145. try:
  146. msu = MySmartUsb(dev, debug)
  147. for action in actions:
  148. if action[0] == "reset-board":
  149. msu.resetBoard()
  150. elif action[0] == "reset-prog":
  151. msu.resetProg()
  152. elif action[0] == "power":
  153. msu.power(action[1])
  154. elif action[0] == "mode":
  155. msu.setMode(action[1])
  156. elif action[0] == "getversion":
  157. print(msu.getVersion())
  158. else:
  159. assert(0)
  160. msu.close()
  161. except MySmartUsbError as e:
  162. print("ERROR: " + str(e))
  163. return 1
  164. return 0
  165. if __name__ == "__main__":
  166. sys.exit(main())