header_generator.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. """This script generates the XAP protocol generated header to be compiled into QMK.
  2. """
  3. import re
  4. from fnvhash import fnv1a_32
  5. from qmk.commands import dump_lines
  6. from qmk.git import git_get_version
  7. from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
  8. from qmk.xap.common import latest_xap_defs, route_conditions
  9. def _append_route_defines(lines, container, container_id=None, route_stack=None):
  10. """Handles building the list of the XAP routes, combining parent and child names together, as well as the route number.
  11. """
  12. if route_stack is None:
  13. route_stack = [container]
  14. else:
  15. route_stack.append(container)
  16. route_name = '_'.join([r['define'] for r in route_stack])
  17. if container_id:
  18. lines.append(f'#define {route_name} {container_id}')
  19. if 'routes' in container:
  20. for route_id in container['routes']:
  21. route = container['routes'][route_id]
  22. _append_route_defines(lines, route, route_id, route_stack)
  23. route_stack.pop()
  24. def _append_route_masks(lines, container, container_id=None, route_stack=None):
  25. """Handles creating the equivalent XAP route masks, for capabilities checks. Forces value of `0` if disabled in the firmware.
  26. """
  27. if route_stack is None:
  28. route_stack = [container]
  29. else:
  30. route_stack.append(container)
  31. route_name = '_'.join([r['define'] for r in route_stack])
  32. condition = route_conditions(route_stack)
  33. if container_id:
  34. if condition:
  35. lines.append('')
  36. lines.append(f'#if {condition}')
  37. lines.append(f'#define {route_name}_MASK (1ul << ({route_name}))')
  38. if condition:
  39. lines.append(f'#else // {condition}')
  40. lines.append(f'#define {route_name}_MASK 0')
  41. lines.append(f'#endif // {condition}')
  42. lines.append('')
  43. if 'routes' in container:
  44. for route_id in container['routes']:
  45. route = container['routes'][route_id]
  46. _append_route_masks(lines, route, route_id, route_stack)
  47. route_stack.pop()
  48. def _append_route_capabilities(lines, container, container_id=None, route_stack=None):
  49. """Handles creating the equivalent XAP route masks, for capabilities checks. Forces value of `0` if disabled in the firmware.
  50. """
  51. if route_stack is None:
  52. route_stack = [container]
  53. else:
  54. route_stack.append(container)
  55. route_name = '_'.join([r['define'] for r in route_stack])
  56. if 'routes' in container:
  57. lines.append('')
  58. lines.append(f'#define {route_name}_CAPABILITIES (0 \\')
  59. if 'routes' in container:
  60. for route_id in container['routes']:
  61. route = container['routes'][route_id]
  62. route_stack.append(route)
  63. child_name = '_'.join([r['define'] for r in route_stack])
  64. lines.append(f' | ({child_name}_MASK) \\')
  65. route_stack.pop()
  66. lines.append(' )')
  67. if 'routes' in container:
  68. for route_id in container['routes']:
  69. route = container['routes'][route_id]
  70. _append_route_capabilities(lines, route, route_id, route_stack)
  71. route_stack.pop()
  72. def generate_header(output_file, keyboard):
  73. """Generates the XAP protocol header file, generated during normal build.
  74. """
  75. xap_defs = latest_xap_defs()
  76. # Preamble
  77. lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '']
  78. # Versions
  79. prog = re.compile(r'^(\d+)\.(\d+)\.(\d+)')
  80. b = prog.match(xap_defs['version'])
  81. lines.append(f'#define XAP_BCD_VERSION 0x{int(b.group(1)):02d}{int(b.group(2)):02d}{int(b.group(3)):04d}ul')
  82. b = prog.match(git_get_version() or "")
  83. lines.append(f'#define QMK_BCD_VERSION 0x{int(b.group(1)):02d}{int(b.group(2)):02d}{int(b.group(3)):04d}ul')
  84. keyboard_id = fnv1a_32(bytes(keyboard, 'utf-8'))
  85. lines.append(f'#define XAP_KEYBOARD_IDENTIFIER 0x{keyboard_id:08X}ul')
  86. lines.append('')
  87. # Append the route and command defines
  88. _append_route_defines(lines, xap_defs)
  89. lines.append('')
  90. _append_route_masks(lines, xap_defs)
  91. lines.append('')
  92. _append_route_capabilities(lines, xap_defs)
  93. lines.append('')
  94. dump_lines(output_file, lines)