creamygoat

WeeSAP - Sixaxis pairing Python script (a Linux altenative to the Sixaxis Pair Tool)

Nov 23rd, 2021 (edited)
819
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.09 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. """WeeSAP - Wee Sixaxis Pairing script
  4.  
  5. This script is a Linux command-line tool used to set the Bluetooth
  6. MAC address of a host to which a USB-connected PS3 Sixaxis controller
  7. will connect. It does the same job as SixaxisPairTool.
  8.  
  9. If no argument is supplied, the current host Bluetooth MAC
  10. address is displayed. (This is distinct from the MAC address of
  11. the PS3 controller itself.)
  12.  
  13. Setting a new host Bluetooth MAC address on a PS3 controller
  14. will allow a microcontroller such as an ESP32-WROOM using the
  15. PS3 Controller Host library to accept a connection from a PS3
  16. controller.
  17.  
  18. A standard HID library (package "python3-hid") is used to send
  19. the 8-byte packet that does the magic. Though sudo will likely
  20. be needed to execute this script, no change to security policies
  21. is required. (When using sudo, the full path to this script may
  22. be required, since root's PATH variable is usually not the same
  23. as that if the user.)
  24.  
  25. A minimal implementation would be
  26.  
  27.  import hid
  28.  device = hid.device()
  29.  device.open(0x054c, 0x0268)
  30.  device.send_feature_report(b'\xF5\x00\xBA\xD4\xCA\xFE\xF0\x0D')
  31.  device.close()
  32.  
  33. to set a PS3 controller's host address to BA:D4:CA:FE:F0:0D.
  34. """
  35.  
  36. import sys  # for access to command line arguments
  37. import hid  # far access to the HDI API
  38.  
  39.  
  40. # Vendor and product IDs for a Sony PS3 Sixaxis controller
  41. VENDOR_ID = 0x054c
  42. PRODUCT_ID = 0x0268
  43.  
  44.  
  45. def bytes_to_mac_str(mac_bytes, sep=":"):
  46.   return sep.join(("{:02x}".format(x) for x in mac_bytes))
  47.  
  48.  
  49. def mac_str_to_bytes(mac_str):
  50.   result = bytearray(6)
  51.   failed = False
  52.   seps = ''
  53.   if len(mac_str) == 17:
  54.     # 10:32:54:76:98:BA or 10-32-54-76-98-BA
  55.     stride = 3
  56.     fwidth = 2
  57.     nfields = 6
  58.     seps = mac_str[2 : : stride]
  59.     failed = seps not in (":::::", "-----")
  60.   elif len(mac_str) == 14:
  61.     # 3210.7654.BA98
  62.     stride = 5
  63.     fwidth = 4
  64.     nfields = 3
  65.     seps = mac_str[4 : : stride]
  66.     failed = seps not in ("..")
  67.   elif len(mac_str) == 12:
  68.     # 1032547698BA
  69.     stride = 2
  70.     fwidth = 2
  71.     nfields = 6
  72.   else:
  73.     failed = True
  74.   if not failed:
  75.     ri = 0
  76.     try:
  77.       for fi in range(nfields):
  78.         field = mac_str[stride * fi : stride * fi + fwidth]
  79.         x = int(field, 16)
  80.         for bi in range(fwidth >> 1):
  81.           result[ri] = x & 255
  82.           x >>= 8
  83.           ri += 1
  84.     except ValueError:
  85.       failed = True
  86.   return None if failed else result
  87.  
  88.  
  89. def main():
  90.  
  91.   do_show_usage = False
  92.   args = list(sys.argv)[1:]
  93.   s = "--help"
  94.   while s in args:
  95.     print("{}: SixAxis Pairing PYthon script".format(sys.argv[0]))
  96.     do_show_usage = True
  97.     del args[args.index(s)]
  98.  
  99.   device = None
  100.   rc = 0
  101.   errmsg = ""
  102.   vpstr = "{:04x}:{:04x}".format(VENDOR_ID, PRODUCT_ID)
  103.   mb = None
  104.  
  105.   if len(args) > 1:
  106.     rc = 1
  107.     errmsg = "Too many arguments!"
  108.     do_show_usage = True
  109.   elif len(args) == 1:
  110.     mb = mac_str_to_bytes(args[0])
  111.     if mb is None:
  112.       rc = 1
  113.       errmsg = "Invalid MAC address"
  114.  
  115.   if rc == 0:
  116.     try:
  117.       device = hid.device()
  118.       device.open(VENDOR_ID, PRODUCT_ID)
  119.     except OSError:
  120.       if device is None:
  121.         rc = 2
  122.         errmsg = "Could not access HID system."
  123.       else:
  124.         rc = 3
  125.         errmsg = (f"Could not open HID device {vpstr}. "
  126.                   "(Privileged access may be required.)")
  127.       device = None
  128.  
  129.   if device:
  130.     try:
  131.       report = device.get_feature_report(0xF5, 8)
  132.       host_mac_str = bytes_to_mac_str(report[2:8])
  133.       if mb is not None:
  134.         msg = bytearray([0xF5, 0x00]) + mb
  135.         r = device.send_feature_report(msg)
  136.         if r == 0:
  137.           rc = 4
  138.           errmsg = "Failed to set host address on controller."
  139.       else:
  140.         print(host_mac_str)
  141.     except:
  142.       rc = 5
  143.       errmsg = "A mysterious error occurred."
  144.     finally:
  145.       device.close()
  146.  
  147.   if errmsg:
  148.     print("{}: {}".format(sys.argv[0], errmsg), file=sys.stderr)
  149.   if do_show_usage:
  150.     print("Usage: {}".format(sys.argv[0]))
  151.     print("       {} NEW_HOST_MAC".format(sys.argv[0]))
  152.   return rc
  153.  
  154.  
  155. if __name__ == '__main__':
  156.   main()
  157.  
Add Comment
Please, Sign In to add comment