make-pins.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. #!/usr/bin/env python
  2. """Creates the pin file for the nRF5."""
  3. from __future__ import print_function
  4. import argparse
  5. import sys
  6. import csv
  7. SUPPORTED_FN = {
  8. 'UART' : ['RX', 'TX', 'CTS', 'RTS']
  9. }
  10. def parse_pin(name_str):
  11. """Parses a string and returns a pin-num."""
  12. if len(name_str) < 1:
  13. raise ValueError("Expecting pin name to be at least 4 charcters.")
  14. if name_str[0] != 'P':
  15. raise ValueError("Expecting pin name to start with P")
  16. pin_str = name_str[1:].split('/')[0]
  17. if not pin_str.isdigit():
  18. raise ValueError("Expecting numeric pin number.")
  19. return int(pin_str)
  20. def split_name_num(name_num):
  21. num = None
  22. for num_idx in range(len(name_num) - 1, -1, -1):
  23. if not name_num[num_idx].isdigit():
  24. name = name_num[0:num_idx + 1]
  25. num_str = name_num[num_idx + 1:]
  26. if len(num_str) > 0:
  27. num = int(num_str)
  28. break
  29. return name, num
  30. class AlternateFunction(object):
  31. """Holds the information associated with a pins alternate function."""
  32. def __init__(self, idx, af_str):
  33. self.idx = idx
  34. self.af_str = af_str
  35. self.func = ''
  36. self.fn_num = None
  37. self.pin_type = ''
  38. self.supported = False
  39. af_words = af_str.split('_', 1)
  40. self.func, self.fn_num = split_name_num(af_words[0])
  41. if len(af_words) > 1:
  42. self.pin_type = af_words[1]
  43. if self.func in SUPPORTED_FN:
  44. pin_types = SUPPORTED_FN[self.func]
  45. if self.pin_type in pin_types:
  46. self.supported = True
  47. def is_supported(self):
  48. return self.supported
  49. def ptr(self):
  50. """Returns the numbered function (i.e. USART6) for this AF."""
  51. if self.fn_num is None:
  52. return self.func
  53. return '{:s}{:d}'.format(self.func, self.fn_num)
  54. def mux_name(self):
  55. return 'AF{:d}_{:s}'.format(self.idx, self.ptr())
  56. def print(self):
  57. """Prints the C representation of this AF."""
  58. if self.supported:
  59. print(' AF', end='')
  60. else:
  61. print(' //', end='')
  62. fn_num = self.fn_num
  63. if fn_num is None:
  64. fn_num = 0
  65. print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx,
  66. self.func, fn_num, self.pin_type, self.ptr(), self.af_str))
  67. def qstr_list(self):
  68. return [self.mux_name()]
  69. class Pin(object):
  70. """Holds the information associated with a pin."""
  71. def __init__(self, pin):
  72. self.pin = pin
  73. self.alt_fn = []
  74. self.alt_fn_count = 0
  75. self.adc_num = 0
  76. self.adc_channel = 0
  77. self.board_pin = False
  78. def cpu_pin_name(self):
  79. return '{:s}{:d}'.format("P", self.pin)
  80. def is_board_pin(self):
  81. return self.board_pin
  82. def set_is_board_pin(self):
  83. self.board_pin = True
  84. def parse_adc(self, adc_str):
  85. if (adc_str[:3] != 'ADC'):
  86. return
  87. (adc,channel) = adc_str.split('_')
  88. for idx in range(3, len(adc)):
  89. self.adc_num = int(adc[idx])
  90. self.adc_channel = int(channel[2:])
  91. def parse_af(self, af_idx, af_strs_in):
  92. if len(af_strs_in) == 0:
  93. return
  94. # If there is a slash, then the slash separates 2 aliases for the
  95. # same alternate function.
  96. af_strs = af_strs_in.split('/')
  97. for af_str in af_strs:
  98. alt_fn = AlternateFunction(af_idx, af_str)
  99. self.alt_fn.append(alt_fn)
  100. if alt_fn.is_supported():
  101. self.alt_fn_count += 1
  102. def alt_fn_name(self, null_if_0=False):
  103. if null_if_0 and self.alt_fn_count == 0:
  104. return 'NULL'
  105. return 'pin_{:s}_af'.format(self.cpu_pin_name())
  106. def adc_num_str(self):
  107. str = ''
  108. for adc_num in range(1,4):
  109. if self.adc_num & (1 << (adc_num - 1)):
  110. if len(str) > 0:
  111. str += ' | '
  112. str += 'PIN_ADC'
  113. str += chr(ord('0') + adc_num)
  114. if len(str) == 0:
  115. str = '0'
  116. return str
  117. def print_const_table_entry(self):
  118. print(' PIN({:d}, {:s}, {:s}, {:d}),'.format(
  119. self.pin,
  120. self.alt_fn_name(null_if_0=True),
  121. self.adc_num_str(), self.adc_channel))
  122. def print(self):
  123. if self.alt_fn_count == 0:
  124. print("// ", end='')
  125. print('const pin_af_obj_t {:s}[] = {{'.format(self.alt_fn_name()))
  126. for alt_fn in self.alt_fn:
  127. alt_fn.print()
  128. if self.alt_fn_count == 0:
  129. print("// ", end='')
  130. print('};')
  131. print('')
  132. print('const pin_obj_t pin_{:s} = PIN({:d}, {:s}, {:s}, {:d});'.format(
  133. self.cpu_pin_name(), self.pin,
  134. self.alt_fn_name(null_if_0=True),
  135. self.adc_num_str(), self.adc_channel))
  136. print('')
  137. def print_header(self, hdr_file):
  138. hdr_file.write('extern const pin_obj_t pin_{:s};\n'.
  139. format(self.cpu_pin_name()))
  140. if self.alt_fn_count > 0:
  141. hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.
  142. format(self.cpu_pin_name()))
  143. def qstr_list(self):
  144. result = []
  145. for alt_fn in self.alt_fn:
  146. if alt_fn.is_supported():
  147. result += alt_fn.qstr_list()
  148. return result
  149. class NamedPin(object):
  150. def __init__(self, name, pin):
  151. self._name = name
  152. self._pin = pin
  153. def pin(self):
  154. return self._pin
  155. def name(self):
  156. return self._name
  157. class Pins(object):
  158. def __init__(self):
  159. self.cpu_pins = [] # list of NamedPin objects
  160. self.board_pins = [] # list of NamedPin objects
  161. def find_pin(self, pin_num):
  162. for named_pin in self.cpu_pins:
  163. pin = named_pin.pin()
  164. if pin.pin == pin_num:
  165. return pin
  166. def parse_af_file(self, filename, pinname_col, af_col, af_col_end):
  167. with open(filename, 'r') as csvfile:
  168. rows = csv.reader(csvfile)
  169. for row in rows:
  170. try:
  171. pin_num = parse_pin(row[pinname_col])
  172. except:
  173. continue
  174. pin = Pin(pin_num)
  175. for af_idx in range(af_col, len(row)):
  176. if af_idx < af_col_end:
  177. pin.parse_af(af_idx - af_col, row[af_idx])
  178. elif af_idx == af_col_end:
  179. pin.parse_adc(row[af_idx])
  180. self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin))
  181. def parse_board_file(self, filename):
  182. with open(filename, 'r') as csvfile:
  183. rows = csv.reader(csvfile)
  184. for row in rows:
  185. try:
  186. pin_num = parse_pin(row[1])
  187. except:
  188. continue
  189. pin = self.find_pin(pin_num)
  190. if pin:
  191. pin.set_is_board_pin()
  192. self.board_pins.append(NamedPin(row[0], pin))
  193. def print_named(self, label, named_pins):
  194. print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label))
  195. index = 0
  196. for named_pin in named_pins:
  197. pin = named_pin.pin()
  198. if pin.is_board_pin():
  199. print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&machine_pin_obj[{:d}]) }},'.format(named_pin.name(), index))
  200. index += 1
  201. print('};')
  202. print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label));
  203. def print_const_table(self):
  204. print('')
  205. print('const uint8_t machine_pin_num_of_pins = {:d};'.format(len(self.board_pins)))
  206. print('')
  207. print('const pin_obj_t machine_pin_obj[{:d}] = {{'.format(len(self.board_pins)))
  208. for named_pin in self.cpu_pins:
  209. pin = named_pin.pin()
  210. if pin.is_board_pin():
  211. pin.print_const_table_entry()
  212. print('};');
  213. def print(self):
  214. self.print_named('cpu', self.cpu_pins)
  215. print('')
  216. self.print_named('board', self.board_pins)
  217. def print_adc(self, adc_num):
  218. print('');
  219. print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num))
  220. for channel in range(16):
  221. adc_found = False
  222. for named_pin in self.cpu_pins:
  223. pin = named_pin.pin()
  224. if (pin.is_board_pin() and
  225. (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)):
  226. print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel))
  227. adc_found = True
  228. break
  229. if not adc_found:
  230. print(' NULL, // {:d}'.format(channel))
  231. print('};')
  232. def print_header(self, hdr_filename):
  233. with open(hdr_filename, 'wt') as hdr_file:
  234. for named_pin in self.cpu_pins:
  235. pin = named_pin.pin()
  236. if pin.is_board_pin():
  237. pin.print_header(hdr_file)
  238. hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n')
  239. hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n')
  240. hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n')
  241. def print_qstr(self, qstr_filename):
  242. with open(qstr_filename, 'wt') as qstr_file:
  243. qstr_set = set([])
  244. for named_pin in self.cpu_pins:
  245. pin = named_pin.pin()
  246. if pin.is_board_pin():
  247. qstr_set |= set(pin.qstr_list())
  248. qstr_set |= set([named_pin.name()])
  249. for named_pin in self.board_pins:
  250. qstr_set |= set([named_pin.name()])
  251. for qstr in sorted(qstr_set):
  252. print('Q({})'.format(qstr), file=qstr_file)
  253. def print_af_hdr(self, af_const_filename):
  254. with open(af_const_filename, 'wt') as af_const_file:
  255. af_hdr_set = set([])
  256. mux_name_width = 0
  257. for named_pin in self.cpu_pins:
  258. pin = named_pin.pin()
  259. if pin.is_board_pin():
  260. for af in pin.alt_fn:
  261. if af.is_supported():
  262. mux_name = af.mux_name()
  263. af_hdr_set |= set([mux_name])
  264. if len(mux_name) > mux_name_width:
  265. mux_name_width = len(mux_name)
  266. for mux_name in sorted(af_hdr_set):
  267. key = 'MP_ROM_QSTR(MP_QSTR_{}),'.format(mux_name)
  268. val = 'MP_ROM_INT(GPIO_{})'.format(mux_name)
  269. print(' { %-*s %s },' % (mux_name_width + 26, key, val),
  270. file=af_const_file)
  271. def print_af_py(self, af_py_filename):
  272. with open(af_py_filename, 'wt') as af_py_file:
  273. print('PINS_AF = (', file=af_py_file);
  274. for named_pin in self.board_pins:
  275. print(" ('%s', " % named_pin.name(), end='', file=af_py_file)
  276. for af in named_pin.pin().alt_fn:
  277. if af.is_supported():
  278. print("(%d, '%s'), " % (af.idx, af.af_str), end='', file=af_py_file)
  279. print('),', file=af_py_file)
  280. print(')', file=af_py_file)
  281. def main():
  282. parser = argparse.ArgumentParser(
  283. prog="make-pins.py",
  284. usage="%(prog)s [options] [command]",
  285. description="Generate board specific pin file"
  286. )
  287. parser.add_argument(
  288. "-a", "--af",
  289. dest="af_filename",
  290. help="Specifies the alternate function file for the chip",
  291. default="nrf.csv"
  292. )
  293. parser.add_argument(
  294. "--af-const",
  295. dest="af_const_filename",
  296. help="Specifies header file for alternate function constants.",
  297. default="build/pins_af_const.h"
  298. )
  299. parser.add_argument(
  300. "--af-py",
  301. dest="af_py_filename",
  302. help="Specifies the filename for the python alternate function mappings.",
  303. default="build/pins_af.py"
  304. )
  305. parser.add_argument(
  306. "-b", "--board",
  307. dest="board_filename",
  308. help="Specifies the board file",
  309. )
  310. parser.add_argument(
  311. "-p", "--prefix",
  312. dest="prefix_filename",
  313. help="Specifies beginning portion of generated pins file",
  314. default="nrf52_prefix.c"
  315. )
  316. parser.add_argument(
  317. "-q", "--qstr",
  318. dest="qstr_filename",
  319. help="Specifies name of generated qstr header file",
  320. default="build/pins_qstr.h"
  321. )
  322. parser.add_argument(
  323. "-r", "--hdr",
  324. dest="hdr_filename",
  325. help="Specifies name of generated pin header file",
  326. default="build/pins.h"
  327. )
  328. args = parser.parse_args(sys.argv[1:])
  329. pins = Pins()
  330. print('// This file was automatically generated by make-pins.py')
  331. print('//')
  332. if args.af_filename:
  333. print('// --af {:s}'.format(args.af_filename))
  334. pins.parse_af_file(args.af_filename, 1, 2, 2)
  335. if args.board_filename:
  336. print('// --board {:s}'.format(args.board_filename))
  337. pins.parse_board_file(args.board_filename)
  338. if args.prefix_filename:
  339. print('// --prefix {:s}'.format(args.prefix_filename))
  340. print('')
  341. with open(args.prefix_filename, 'r') as prefix_file:
  342. print(prefix_file.read())
  343. pins.print_const_table()
  344. pins.print()
  345. pins.print_header(args.hdr_filename)
  346. pins.print_qstr(args.qstr_filename)
  347. pins.print_af_hdr(args.af_const_filename)
  348. pins.print_af_py(args.af_py_filename)
  349. if __name__ == "__main__":
  350. main()