You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
7.3KB

  1. #!/usr/bin/python2.5
  2. #
  3. # Copyright 2013 Olivier Gillet.
  4. #
  5. # Author: Olivier Gillet (ol.gillet@gmail.com)
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a copy
  8. # of this software and associated documentation files (the "Software"), to deal
  9. # in the Software without restriction, including without limitation the rights
  10. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. # copies of the Software, and to permit persons to whom the Software is
  12. # furnished to do so, subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be included in
  15. # all copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. # THE SOFTWARE.
  24. #
  25. # See http://creativecommons.org/licenses/MIT/ for more information.
  26. #
  27. # -----------------------------------------------------------------------------
  28. #
  29. # Qpsk encoder for converting firmware .bin files into .
  30. import numpy
  31. import optparse
  32. import zlib
  33. from stm_audio_bootloader import audio_stream_writer
  34. class QpskEncoder(object):
  35. def __init__(
  36. self,
  37. sample_rate=48000,
  38. carrier_frequency=2000,
  39. bit_rate=8000,
  40. packet_size=256):
  41. period = sample_rate / carrier_frequency
  42. symbol_time = sample_rate / (bit_rate / 2)
  43. assert (symbol_time % period == 0) or (period % symbol_time == 0)
  44. assert (sample_rate % carrier_frequency) == 0
  45. assert (sample_rate % bit_rate) == 0
  46. self._sr = sample_rate
  47. self._br = bit_rate
  48. self._carrier_frequency = carrier_frequency
  49. self._sample_index = 0
  50. self._packet_size = packet_size
  51. @staticmethod
  52. def _upsample(x, factor):
  53. return numpy.tile(x.reshape(len(x), 1), (1, factor)).ravel()
  54. def _encode_qpsk(self, symbol_stream):
  55. ratio = self._sr / self._br * 2
  56. symbol_stream = numpy.array(symbol_stream)
  57. bitstream_even = 2 * self._upsample(symbol_stream % 2, ratio) - 1
  58. bitstream_odd = 2 * self._upsample(symbol_stream / 2, ratio) - 1
  59. return bitstream_even / numpy.sqrt(2.0), bitstream_odd / numpy.sqrt(2.0)
  60. def _modulate(self, q_mod, i_mod):
  61. num_samples = len(q_mod)
  62. t = (numpy.arange(0.0, num_samples) + self._sample_index) / self._sr
  63. self._sample_index += num_samples
  64. phase = 2 * numpy.pi * self._carrier_frequency * t
  65. return (q_mod * numpy.sin(phase) + i_mod * numpy.cos(phase))
  66. def _encode(self, symbol_stream):
  67. return self._modulate(*self._encode_qpsk(symbol_stream))
  68. def _code_blank(self, duration):
  69. num_zeros = int(duration * self._br / 8) * 4
  70. symbol_stream = numpy.zeros((num_zeros, 1)).ravel().astype(int)
  71. return self._encode(symbol_stream)
  72. def _code_packet(self, data):
  73. assert len(data) <= self._packet_size
  74. if len(data) != self._packet_size:
  75. data = data + '\x00' * (self._packet_size - len(data))
  76. crc = zlib.crc32(data) & 0xffffffff
  77. data = map(ord, data)
  78. # 16x 0 for the PLL ; 8x 21 for the edge detector ; 8x 3030 for syncing
  79. preamble = [0] * 8 + [0x99] * 4 + [0xcc] * 4
  80. crc_bytes = [crc >> 24, (crc >> 16) & 0xff, (crc >> 8) & 0xff, crc & 0xff]
  81. bytes = preamble + data + crc_bytes
  82. symbol_stream = []
  83. for byte in bytes:
  84. symbol_stream.append((byte >> 6) & 0x3)
  85. symbol_stream.append((byte >> 4) & 0x3)
  86. symbol_stream.append((byte >> 2) & 0x3)
  87. symbol_stream.append((byte >> 0) & 0x3)
  88. return self._encode(symbol_stream)
  89. def code_intro(self):
  90. yield numpy.zeros((1.0 * self._sr, 1)).ravel()
  91. yield self._code_blank(1.0)
  92. def code_outro(self, duration=1.0):
  93. yield self._code_blank(duration)
  94. def code(self, data, page_size=1024, blank_duration=0.06):
  95. if len(data) % page_size != 0:
  96. tail = page_size - (len(data) % page_size)
  97. data += '\xff' * tail
  98. offset = 0
  99. remaining_bytes = len(data)
  100. num_packets_written = 0
  101. while remaining_bytes:
  102. size = min(remaining_bytes, self._packet_size)
  103. yield self._code_packet(data[offset:offset+size])
  104. num_packets_written += 1
  105. if num_packets_written == page_size / self._packet_size:
  106. yield self._code_blank(blank_duration)
  107. num_packets_written = 0
  108. remaining_bytes -= size
  109. offset += size
  110. STM32F4_SECTOR_BASE_ADDRESS = [
  111. 0x08000000,
  112. 0x08004000,
  113. 0x08008000,
  114. 0x0800C000,
  115. 0x08010000,
  116. 0x08020000,
  117. 0x08040000,
  118. 0x08060000,
  119. 0x08080000,
  120. 0x080A0000,
  121. 0x080C0000,
  122. 0x080E0000
  123. ]
  124. STM32F1_PAGE_SIZE = 1024
  125. STM32F4_BLOCK_SIZE = 16384
  126. STM32F4_APPLICATION_START = 0x08008000
  127. def main():
  128. parser = optparse.OptionParser()
  129. parser.add_option(
  130. '-s',
  131. '--sample_rate',
  132. dest='sample_rate',
  133. type='int',
  134. default=48000,
  135. help='Sample rate in Hz')
  136. parser.add_option(
  137. '-c',
  138. '--carrier_frequency',
  139. dest='carrier_frequency',
  140. type='int',
  141. default=6000,
  142. help='Carrier frequency in Hz')
  143. parser.add_option(
  144. '-b',
  145. '--baud_rate',
  146. dest='baud_rate',
  147. type='int',
  148. default=12000,
  149. help='Baudrate in bps')
  150. parser.add_option(
  151. '-p',
  152. '--packet_size',
  153. dest='packet_size',
  154. type='int',
  155. default=256,
  156. help='Packet size in bytes')
  157. parser.add_option(
  158. '-o',
  159. '--output_file',
  160. dest='output_file',
  161. default=None,
  162. help='Write output file to FILE',
  163. metavar='FILE')
  164. parser.add_option(
  165. '-t',
  166. '--target',
  167. dest='target',
  168. default='stm32f1',
  169. help='Set page size and erase time for TARGET',
  170. metavar='TARGET')
  171. options, args = parser.parse_args()
  172. data = file(args[0], 'rb').read()
  173. if len(args) != 1:
  174. logging.fatal('Specify one, and only one firmware .bin file!')
  175. sys.exit(1)
  176. if options.target not in ['stm32f1', 'stm32f4']:
  177. logging.fatal('Unknown target: %s' % options.target)
  178. sys.exit(2)
  179. output_file = options.output_file
  180. if not output_file:
  181. if '.bin' in args[0]:
  182. output_file = args[0].replace('.bin', '.wav')
  183. else:
  184. output_file = args[0] + '.wav'
  185. encoder = QpskEncoder(
  186. options.sample_rate,
  187. options.carrier_frequency,
  188. options.baud_rate,
  189. options.packet_size)
  190. writer = audio_stream_writer.AudioStreamWriter(
  191. output_file,
  192. options.sample_rate,
  193. 16,
  194. 1)
  195. # INTRO
  196. for block in encoder.code_intro():
  197. writer.append(block)
  198. blank_duration = 1.0
  199. if options.target == 'stm32f1':
  200. for block in encoder.code(data, STM32F1_PAGE_SIZE, 0.06):
  201. if len(block):
  202. writer.append(block)
  203. elif options.target == 'stm32f4':
  204. for x in xrange(0, len(data), STM32F4_BLOCK_SIZE):
  205. address = STM32F4_APPLICATION_START + x
  206. block = data[x:x+STM32F4_BLOCK_SIZE]
  207. pause = 2.5 if address in STM32F4_SECTOR_BASE_ADDRESS else 0.2
  208. for block in encoder.code(block, STM32F4_BLOCK_SIZE, pause):
  209. if len(block):
  210. writer.append(block)
  211. blank_duration = 5.0
  212. for block in encoder.code_outro(blank_duration):
  213. writer.append(block)
  214. if __name__ == '__main__':
  215. main()