test_fingerprints.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #!/usr/bin/env python3
  2. import os
  3. import sys
  4. from openpilot.common.basedir import BASEDIR
  5. # messages reserved for CAN based ignition (see can_ignition_hook function in panda/board/drivers/can)
  6. # (addr, len)
  7. CAN_IGNITION_MSGS = {
  8. 'gm': [(0x1F1, 8), (0x160, 5)],
  9. #'tesla' : [(0x348, 8)],
  10. }
  11. def _get_fingerprints():
  12. # read all the folders in selfdrive/car and return a dict where:
  13. # - keys are all the car names that which we have a fingerprint dict for
  14. # - values are dicts of fingeprints for each trim
  15. fingerprints = {}
  16. for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]:
  17. car_name = car_folder.split('/')[-1]
  18. try:
  19. fingerprints[car_name] = __import__(f'selfdrive.car.{car_name}.values', fromlist=['FINGERPRINTS']).FINGERPRINTS
  20. except (ImportError, OSError, AttributeError):
  21. pass
  22. return fingerprints
  23. def check_fingerprint_consistency(f1, f2):
  24. # return false if it finds a fingerprint fully included in another
  25. # max message worth checking is 1800, as above that they usually come too infrequently and not
  26. # usable for fingerprinting
  27. max_msg = 1800
  28. is_f1_in_f2 = True
  29. for k in f1:
  30. if (k not in f2 or f1[k] != f2[k]) and k < max_msg:
  31. is_f1_in_f2 = False
  32. is_f2_in_f1 = True
  33. for k in f2:
  34. if (k not in f1 or f2[k] != f1[k]) and k < max_msg:
  35. is_f2_in_f1 = False
  36. return not is_f1_in_f2 and not is_f2_in_f1
  37. def check_can_ignition_conflicts(fingerprints, brands):
  38. # loops through all the fingerprints and exits if CAN ignition dedicated messages
  39. # are found in unexpected fingerprints
  40. for brand_can, msgs_can in CAN_IGNITION_MSGS.items():
  41. for i, f in enumerate(fingerprints):
  42. for msg_can in msgs_can:
  43. if brand_can != brands[i] and msg_can[0] in f and msg_can[1] == f[msg_can[0]]:
  44. print("CAN ignition dedicated msg %d with len %d found in %s fingerprints!" % (msg_can[0], msg_can[1], brands[i]))
  45. print("TEST FAILED")
  46. sys.exit(1)
  47. if __name__ == "__main__":
  48. fingerprints = _get_fingerprints()
  49. fingerprints_flat: list[dict] = []
  50. car_names = []
  51. brand_names = []
  52. for brand in fingerprints:
  53. for car in fingerprints[brand]:
  54. fingerprints_flat += fingerprints[brand][car]
  55. for _ in range(len(fingerprints[brand][car])):
  56. car_names.append(car)
  57. brand_names.append(brand)
  58. # first check if CAN ignition specific messages are unexpectedly included in other fingerprints
  59. check_can_ignition_conflicts(fingerprints_flat, brand_names)
  60. valid = True
  61. for idx1, f1 in enumerate(fingerprints_flat):
  62. for idx2, f2 in enumerate(fingerprints_flat):
  63. if idx1 < idx2 and not check_fingerprint_consistency(f1, f2):
  64. valid = False
  65. print(f"Those two fingerprints are inconsistent {car_names[idx1]} {car_names[idx2]}")
  66. print("")
  67. print(', '.join("%d: %d" % v for v in sorted(f1.items())))
  68. print("")
  69. print(', '.join("%d: %d" % v for v in sorted(f2.items())))
  70. print("")
  71. print(f"Found {len(fingerprints_flat)} individual fingerprints")
  72. if not valid or len(fingerprints_flat) == 0:
  73. print("TEST FAILED")
  74. sys.exit(1)
  75. else:
  76. print("TEST SUCCESSFUL")