bitfile.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. """
  2. # *.BIT file parser
  3. #
  4. # Copyright (c) 2009-2021 Michael Buesch <m@bues.ch>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  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. # You should have received a copy of the GNU General Public License along
  17. # with this program; if not, write to the Free Software Foundation, Inc.,
  18. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. """
  20. import sys
  21. try:
  22. import pkg_resources
  23. except ImportError:
  24. print("Failed to import the 'pkg_resources' Python module.")
  25. print("'pkg_resources' is part of the Python 'setuptools' package.")
  26. print("On Debian Linux run: apt-get install python3-pkg-resources")
  27. sys.exit(1)
  28. from libtoprammer.util import *
  29. class BitfileException(Exception): pass
  30. class Bitfile:
  31. # Magic header
  32. MAGIC = b"\x00\x09\x0f\xf0\x0f\xf0\x0f\xf0\x0f\xf0\x00\x00\x01"
  33. # Field IDs
  34. FIELD_SRCFILE = 0x61
  35. FIELD_FPGA = 0x62
  36. FIELD_DATE = 0x63
  37. FIELD_TIME = 0x64
  38. FIELD_PAYLOAD = 0x65
  39. def __init__(self):
  40. self.filename = ""
  41. self.srcfile = ""
  42. self.fpga = ""
  43. self.date = ""
  44. self.time = ""
  45. self.payload = b""
  46. def getFilename(self):
  47. return self.filename
  48. def getSrcFile(self):
  49. return self.srcfile
  50. def getFPGA(self):
  51. return self.fpga
  52. def getDate(self):
  53. return self.date
  54. def getTime(self):
  55. return self.time
  56. def getPayload(self):
  57. return self.payload
  58. def parseFile(self, filename):
  59. try:
  60. fd = open(filename, "rb")
  61. data = fd.read()
  62. fd.close()
  63. except (IOError) as e:
  64. raise BitfileException("Failed to read \"" + filename + "\": " + e.strerror)
  65. self.filename = filename
  66. self.__parse(data)
  67. def __parse(self, data):
  68. try:
  69. magic = data[0:len(self.MAGIC)]
  70. if magic != self.MAGIC:
  71. raise BitfileException("Invalid magic header")
  72. i = len(self.MAGIC)
  73. while i < len(data):
  74. i += self.__parseNextField(data, i)
  75. except (IndexError) as e:
  76. raise BitfileException("Failed to parse BIT file")
  77. if not self.fpga:
  78. raise BitfileException("No FPGA ID string found")
  79. if not self.payload:
  80. raise BitfileException("No payload found")
  81. def __parseNextField(self, data, i):
  82. fieldId = byte2int(data[i + 0])
  83. if (fieldId == self.FIELD_SRCFILE):
  84. data = self.__parse16bitField(data, i + 1)
  85. self.srcfile = data.decode("ASCII").strip().strip("\x00")
  86. return len(data) + 3
  87. if (fieldId == self.FIELD_FPGA):
  88. data = self.__parse16bitField(data, i + 1)
  89. self.fpga = data.decode("ASCII").strip().strip("\x00")
  90. return len(data) + 3
  91. if (fieldId == self.FIELD_DATE):
  92. data = self.__parse16bitField(data, i + 1)
  93. self.date = data.decode("ASCII").strip().strip("\x00")
  94. return len(data) + 3
  95. if (fieldId == self.FIELD_TIME):
  96. data = self.__parse16bitField(data, i + 1)
  97. self.time = data.decode("ASCII").strip().strip("\x00")
  98. return len(data) + 3
  99. if (fieldId == self.FIELD_PAYLOAD):
  100. self.payload = self.__parse32bitField(data, i + 1)
  101. return len(self.payload) + 5
  102. raise BitfileException("Found unknown data field 0x%02X" % fieldId)
  103. def __parse16bitField(self, data, i):
  104. fieldLen = (byte2int(data[i + 0]) << 8) | byte2int(data[i + 1])
  105. return data[i + 2 : i + 2 + fieldLen]
  106. def __parse32bitField(self, data, i):
  107. fieldLen = (byte2int(data[i + 0]) << 24) | (byte2int(data[i + 1]) << 16) |\
  108. (byte2int(data[i + 2]) << 8) | byte2int(data[i + 3])
  109. return data[i + 4 : i + 4 + fieldLen]
  110. def __probeFile(fullpath):
  111. try:
  112. open(fullpath, "rb").close()
  113. except (IOError) as e:
  114. return False
  115. return True
  116. def bitfileFind(filename):
  117. "Search some standard paths for a bitfile"
  118. if not filename.endswith(".bit"):
  119. filename += ".bit"
  120. if filename.startswith("/"):
  121. if __probeFile(filename):
  122. return filename
  123. paths = ( ".", "./libtoprammer/fpga/bin", )
  124. for path in paths:
  125. fullpath = path + "/" + filename
  126. if __probeFile(fullpath):
  127. return fullpath
  128. fullpath = pkg_resources.resource_filename("libtoprammer",
  129. "fpga/bin/" + filename)
  130. if __probeFile(fullpath):
  131. return fullpath
  132. return None
  133. if __name__ == "__main__":
  134. if len(sys.argv) != 3:
  135. print("Usage: %s file.bit ACTION")
  136. print("")
  137. print("Actions:")
  138. print(" GETSRC - print the src-file field to stdout")
  139. print(" GETFPGA - print the fpga-type field to stdout")
  140. print(" GETDATE - print the date field to stdout")
  141. print(" GETTIME - print the time field to stdout")
  142. print(" GETPAYLOAD - print the payload field to stdout")
  143. sys.exit(1)
  144. filename = sys.argv[1]
  145. action = sys.argv[2].upper()
  146. b = Bitfile()
  147. b.parseFile(filename)
  148. if action == "GETSRC":
  149. sys.stdout.write(b.getSrcFile())
  150. if action == "GETFPGA":
  151. sys.stdout.write(b.getFPGA())
  152. if action == "GETDATE":
  153. sys.stdout.write(b.getDate())
  154. if action == "GETTIME":
  155. sys.stdout.write(b.getTime())
  156. if action == "GETPAYLOAD":
  157. sys.stdout.buffer.write(b.getPayload())