hc4094sniffer.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #!/usr/bin/env python3
  2. """
  3. * 74HC4094 data sniffer
  4. *
  5. * Copyright (C) 2010-2022 Michael Buesch <m@bues.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * version 2 as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. """
  16. import getopt
  17. import sys
  18. import time
  19. try:
  20. from serial import *
  21. except ImportError:
  22. print("ERROR: pyserial module not available.", file=sys.stderr)
  23. print("On Debian Linux please do: apt-get install python3-serial", file=sys.stderr)
  24. sys.exit(1)
  25. # Serial port config
  26. SERIAL_BAUDRATE = 115200
  27. SERIAL_BYTESIZE = 8
  28. SERIAL_PARITY = PARITY_NONE
  29. SERIAL_STOPBITS = 1
  30. class SnifferException(Exception):
  31. pass
  32. class Sniffer:
  33. def __init__(self, tty, numShiftregs):
  34. try:
  35. self.serial = Serial(tty, SERIAL_BAUDRATE,
  36. SERIAL_BYTESIZE, SERIAL_PARITY,
  37. SERIAL_STOPBITS)
  38. self.size = numShiftregs
  39. self.serial.read(self.serial.inWaiting())
  40. self.__doRead(self.size)
  41. except (SerialException, OSError, IOError) as e:
  42. raise SnifferException(str(e))
  43. def clear(self):
  44. self.__doRead(self.size ^ 0xFF)
  45. self.__doRead(self.size)
  46. def __doRead(self, size):
  47. self.serial.write(b"%c" % size)
  48. time.sleep(0.1)
  49. return self.serial.read(self.serial.inWaiting())
  50. def read(self):
  51. try:
  52. data = self.__doRead(self.size)
  53. if len(data) != self.size:
  54. raise SnifferException(
  55. "Unexpected data length. Is %d, expected %d" %\
  56. (len(data), self.size))
  57. return data
  58. except (SerialException, OSError, IOError) as e:
  59. raise SnifferException(str(e))
  60. def toAscii(char):
  61. assert(isinstance(char, int))
  62. if char >= 32 and char <= 126:
  63. return chr(char)
  64. return "."
  65. def dumpMem(mem):
  66. assert(isinstance(mem, (bytes, bytearray)))
  67. ascii = ""
  68. for i in range(len(mem)):
  69. if i % 16 == 0 and i != 0:
  70. print(" " + ascii + "\n", end='')
  71. ascii = ""
  72. if i % 16 == 0:
  73. print("0x%04X: " % i, end='')
  74. c = mem[i]
  75. print("%02X" % c, end='')
  76. if (i % 2 != 0):
  77. print(" ", end='')
  78. ascii += toAscii(c)
  79. print(" " + ascii + "\n")
  80. def usage():
  81. print("Usage: %s TTY NUM_SHIFTREGS" % sys.argv[0], file=sys.stderr)
  82. def main(argv):
  83. try:
  84. tty = argv[1]
  85. numShiftregs = int(argv[2])
  86. except (IndexError, ValueError) as e:
  87. usage()
  88. return 1
  89. try:
  90. s = Sniffer(tty, numShiftregs)
  91. data = s.read()
  92. dumpMem(data)
  93. except SnifferException as e:
  94. print(str(e), file=sys.stderr)
  95. return 0
  96. if __name__ == "__main__":
  97. sys.exit(main(sys.argv))