From 5776281cf0caa63cc02806e0c949442b7e19c65c Mon Sep 17 00:00:00 2001 From: Thomas Perl Date: Fri, 6 Jul 2018 01:20:54 +0200 Subject: [PATCH 01/17] Initial support for PS4 Move Controller --- src/daemon/moved_monitor_linux.c | 2 +- src/daemon/moved_monitor_osx.mm | 2 +- src/psmove.c | 49 +++++++++++++++++++++++++------- src/psmove_private.h | 3 ++ 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/daemon/moved_monitor_linux.c b/src/daemon/moved_monitor_linux.c index 5860f263..76da44bd 100644 --- a/src/daemon/moved_monitor_linux.c +++ b/src/daemon/moved_monitor_linux.c @@ -151,7 +151,7 @@ _moved_monitor_handle_device(moved_monitor *monitor, struct udev_device *dev) &serial_number_utf8, &product_name_utf8)) { wchar_t *serial_number = utf8_to_wchar_t(serial_number_utf8); - if (vendor_id == PSMOVE_VID && product_id == PSMOVE_PID) { + if (vendor_id == PSMOVE_VID && (product_id == PSMOVE_PID || product_id == PSMOVE_PS4_PID)) { if (bus_type == BUS_BLUETOOTH) { device_type = EVENT_DEVICE_TYPE_BLUETOOTH; } else if (bus_type == BUS_USB) { diff --git a/src/daemon/moved_monitor_osx.mm b/src/daemon/moved_monitor_osx.mm index 99ecb983..7f1c2ced 100644 --- a/src/daemon/moved_monitor_osx.mm +++ b/src/daemon/moved_monitor_osx.mm @@ -94,7 +94,7 @@ void pump_loop() void make_event(enum MonitorEvent event, IOHIDDeviceRef device) { - if (get_vendor_id(device) == PSMOVE_VID && get_product_id(device) == PSMOVE_PID) { + if (get_vendor_id(device) == PSMOVE_VID && (get_product_id(device) == PSMOVE_PID || get_product_id(device) == PSMOVE_PS4_PID)) { ASyncDeviceEvent ade; ade.event = event; ade.device_type = EVENT_DEVICE_TYPE_UNKNOWN; diff --git a/src/psmove.c b/src/psmove.c index 3285947d..f4ed941b 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -134,6 +134,12 @@ psmove_decode_16bit(char *data, int offset) return (low | (high << 8)) - 0x8000; } +static int +PSMOVE_PIDS[] = { + PSMOVE_PID, + PSMOVE_PS4_PID, + 0, +}; typedef struct { unsigned char type; /* message type, must be PSMove_Req_GetInput */ @@ -345,17 +351,13 @@ psmove_reinit() hid_exit(); } -int -psmove_count_connected_hidapi() +static int +_psmove_count_connected_by_pid(int pid) { struct hid_device_info *devs, *cur_dev; int count = 0; - if (psmove_local_disabled) { - return 0; - } - - devs = hid_enumerate(PSMOVE_VID, PSMOVE_PID); + devs = hid_enumerate(PSMOVE_VID, pid); cur_dev = devs; while (cur_dev) { #ifdef _WIN32 @@ -376,6 +378,23 @@ psmove_count_connected_hidapi() return count; } +int +psmove_count_connected_hidapi() +{ + int count = 0; + + if (psmove_local_disabled) { + return 0; + } + + int *pid = PSMOVE_PIDS; + while (*pid) { + count += _psmove_count_connected_by_pid(*pid++); + } + + return count; +} + int psmove_count_connected_moved(moved_client *client) { @@ -459,6 +478,9 @@ psmove_connect_internal(const wchar_t *serial, const char *path, int id) move->handle = hid_open_path(path); } else { move->handle = hid_open(PSMOVE_VID, PSMOVE_PID, serial); + if (!move->handle) { + move->handle = hid_open(PSMOVE_VID, PSMOVE_PS4_PID, serial); + } } #endif @@ -596,14 +618,18 @@ _psmove_get_firmware_info(PSMove *move) * while the USB report does not. So we need to check the current connection * type in order to determine the correct offset for reading from the report * buffer. + * + * XXX: This also happens for me on macOS with USB, so check the first + * byte, and if it's the Report ID as first byte, assume we need to remove + * it from the response. **/ - if (psmove_connection_type(move) == Conn_Bluetooth) { - expected_res += 1; - p = buf + 1; + if (psmove_connection_type(move) == Conn_Bluetooth || (res > 0 && buf[0] == PSMove_Req_GetFirmwareInfo)) { + --res; + ++p; } - psmove_return_val_if_fail(res == expected_res, NULL); + psmove_return_val_if_fail(res >= expected_res, NULL); PSMove_Firmware_Info *info = malloc(sizeof(PSMove_Firmware_Info)); @@ -741,6 +767,7 @@ psmove_connect_by_id(int id) struct hid_device_info *devs, *cur_dev; PSMove *move = NULL; + // TODO: FIXME: This needs to add support for PS4 Move still devs = hid_enumerate(PSMOVE_VID, PSMOVE_PID); // Count available devices diff --git a/src/psmove_private.h b/src/psmove_private.h index 2057085a..e0596785 100644 --- a/src/psmove_private.h +++ b/src/psmove_private.h @@ -50,8 +50,11 @@ extern "C" { **/ /* Vendor ID and Product ID of PS Move Controller */ +/* PS3/PS4 PS Move Controller (MiniUSB), a.k.a. CECH-ZCM1E */ #define PSMOVE_VID 0x054c #define PSMOVE_PID 0x03d5 +/* PS4 PS Move Controller (MicroUSB), a.k.a. CECH-ZCM2J */ +#define PSMOVE_PS4_PID 0x0c5e #define psmove_PRINTF(section, msg, ...) \ fprintf(stderr, "[" section "] " msg, ## __VA_ARGS__) From 47f5351a1735e8a452839b169d65093a11f84f73 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 8 Jul 2018 16:26:29 +0200 Subject: [PATCH 02/17] Handle multiple PIDs in psmove_connect_by_id --- src/psmove.c | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/psmove.c b/src/psmove.c index f4ed941b..c22ef78f 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -134,6 +134,9 @@ psmove_decode_16bit(char *data, int offset) return (low | (high << 8)) - 0x8000; } +#define NUM_PSMOVE_PIDS \ + ((sizeof(PSMOVE_PIDS) / sizeof(PSMOVE_PIDS[0])) - 1) + static int PSMOVE_PIDS[] = { PSMOVE_PID, @@ -738,6 +741,8 @@ compare_hid_device_info_ptr(const void *a, const void *b) return 0; } +static struct hid_device_info *move_hid_devices[NUM_PSMOVE_PIDS]; + PSMove * psmove_connect_by_id(int id) { @@ -767,22 +772,38 @@ psmove_connect_by_id(int id) struct hid_device_info *devs, *cur_dev; PSMove *move = NULL; - // TODO: FIXME: This needs to add support for PS4 Move still - devs = hid_enumerate(PSMOVE_VID, PSMOVE_PID); + // TODO: Implement handling of multiple PIDs in a cleaner way. Ideally, we + // would just build a *single* list of hid_device_info structs. + + // enumerate matching HID devices + for (unsigned int i = 0; i < NUM_PSMOVE_PIDS; i++) { + psmove_DEBUG("Enumerating HID devices with PID 0x%04X\n", PSMOVE_PIDS[i]); + + // NOTE: hidapi returns NULL for PIDs that were not found + move_hid_devices[i] = hid_enumerate(PSMOVE_VID, PSMOVE_PIDS[i]); + } // Count available devices int available = 0; - for (cur_dev=devs, available=0; cur_dev != NULL; cur_dev = cur_dev->next, available++); + int i; + for (i = 0; i < NUM_PSMOVE_PIDS; i++) { + for (cur_dev = move_hid_devices[i]; cur_dev != NULL; cur_dev = cur_dev->next, available++); + } + psmove_DEBUG("Matching HID devices: %d\n", available); // Sort list of devices to have stable ordering of devices + int n = 0; struct hid_device_info **devs_sorted = calloc(available, sizeof(struct hid_device_info *)); - cur_dev = devs; - int i; - for (i=0; inext; + for (i = 0; i < NUM_PSMOVE_PIDS; i++) { + cur_dev = move_hid_devices[i]; + while (cur_dev && (n < available)) { + devs_sorted[n] = cur_dev; + cur_dev = cur_dev->next; + n++; + } } qsort((void *)devs_sorted, available, sizeof(struct hid_device_info *), compare_hid_device_info_ptr); + #if defined(PSMOVE_DEBUG) for (i=0; i Date: Sun, 8 Jul 2018 16:38:59 +0200 Subject: [PATCH 03/17] Switch from HID Output report 0x02 to 0x06 Both seem to do the same thing (setting LED color and rumble), but 0x06 also works with the CECH-ZCM2 models. --- src/psmove.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psmove.c b/src/psmove.c index c22ef78f..1dd4aaea 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -51,7 +51,7 @@ /* Begin private definitions */ /* Buffer size for writing LEDs and reading sensor data */ -#define PSMOVE_BUFFER_SIZE 49 +#define PSMOVE_BUFFER_SIZE 9 /* Buffer size for the Bluetooth address get request */ #define PSMOVE_BTADDR_GET_SIZE 16 @@ -71,7 +71,7 @@ enum PSMove_Request_Type { PSMove_Req_GetInput = 0x01, - PSMove_Req_SetLEDs = 0x02, + PSMove_Req_SetLEDs = 0x06, PSMove_Req_SetLEDPWMFrequency = 0x03, PSMove_Req_GetBTAddr = 0x04, PSMove_Req_SetBTAddr = 0x05, From 154bdc0f5e66eed6621ca2ede73da66a3c084f0f Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 8 Jul 2018 18:28:25 +0200 Subject: [PATCH 04/17] Prepare for handling different controller models --- include/psmove.h | 10 ++++++++- src/daemon/moved.cpp | 15 ++++++++++--- src/platform/psmove_port_linux.cpp | 36 +++++++++++++++++------------- src/platform/psmove_port_osx.mm | 4 +++- src/platform/psmove_port_windows.c | 2 ++ src/psmove.c | 22 ++++++++++++------ src/psmove_port.h | 2 +- src/psmove_private.h | 2 +- src/psmoveapi.cpp | 6 ++++- src/utils/psmoveregister.c | 16 ++++++++++--- 10 files changed, 81 insertions(+), 34 deletions(-) diff --git a/include/psmove.h b/include/psmove.h index 03071181..6292b9f2 100644 --- a/include/psmove.h +++ b/include/psmove.h @@ -49,6 +49,13 @@ extern "C" { # define ADDCALL #endif +/*! Hardware model type for controller. + **/ +enum PSMove_Model_Type { + Model_ZCM1, + Model_ZCM2, +}; + /*! Connection type for controllers. * Controllers can be connected via USB or via Bluetooth. The USB connection is * required when you want to pair the controller and for saving the calibration @@ -416,9 +423,10 @@ ADDCALL psmove_pair(PSMove *move); * \brief Add an entry for a controller paired on another host. * * \param addr The Bluetooth address of the PS move to add + * \param model The hardware model type of the controller **/ ADDAPI enum PSMove_Bool -ADDCALL psmove_host_pair_custom(const char *addr); +ADDCALL psmove_host_pair_custom(const char *addr, enum PSMove_Model_Type model); /** * \brief Pair a controller connected via USB to a specific address. diff --git a/src/daemon/moved.cpp b/src/daemon/moved.cpp index d9d4ee8c..4691a89f 100644 --- a/src/daemon/moved.cpp +++ b/src/daemon/moved.cpp @@ -100,7 +100,11 @@ on_monitor_update_moved(enum MonitorEvent event, if (event == EVENT_DEVICE_ADDED) { if (device_type == EVENT_DEVICE_TYPE_USB) { - PSMove *move = psmove_connect_internal(serial, path, -1); + // TODO: FIXME: This should use the device's actual USB product ID. + // HACK: We rely on this invalid PID being translated to a + // valid controller model (the old ZCM1, be default). + unsigned short pid = 0; + PSMove *move = psmove_connect_internal(serial, path, -1, pid); if (psmove_pair(move)) { // Indicate to the user that pairing was successful psmove_set_leds(move, 0, 255, 0); @@ -270,7 +274,8 @@ moved_server::handle_request() char *addr = _psmove_btaddr_to_string(*((PSMove_Data_BTAddr *)&request.register_controller.btaddr)); char *host = psmove_port_get_host_bluetooth_address(); - psmove_port_register_psmove(addr, host); + // TODO: Add support for other models + psmove_port_register_psmove(addr, host, Model_ZCM1); free(addr); free(host); @@ -304,7 +309,11 @@ psmove_dev::psmove_dev(move_daemon *moved, const char *path, const wchar_t *seri : dirty_output(0) { if (path != NULL) { - move = psmove_connect_internal((wchar_t *)serial, (char *)path, moved->count()); + // TODO: FIXME: This should use the device's actual USB product ID. + // HACK: We rely on this invalid PID being translated to a + // valid controller model (the old ZCM1, be default). + unsigned short pid = 0; + move = psmove_connect_internal((wchar_t *)serial, (char *)path, moved->count(), pid); } else { move = psmove_connect_by_id(moved->count()); } diff --git a/src/platform/psmove_port_linux.cpp b/src/platform/psmove_port_linux.cpp index b7924a1a..fbe96ccb 100644 --- a/src/platform/psmove_port_linux.cpp +++ b/src/platform/psmove_port_linux.cpp @@ -57,20 +57,22 @@ namespace { const std::string -BLUEZ5_INFO_ENTRY { -"[General]\n" -"Name=Motion Controller\n" -"Class=0x002508\n" -"SupportedTechnologies=BR/EDR\n" -"Trusted=true\n" -"Blocked=false\n" -"Services=00001124-0000-1000-8000-00805f9b34fb;\n" -"\n" -"[DeviceID]\n" -"Source=1\n" -"Vendor=1356\n" -"Product=981\n" -"Version=1\n" }; +BLUEZ5_INFO_ENTRY(unsigned short pid) { + return + "[General]\n" + "Name=Motion Controller\n" + "Class=0x002508\n" + "SupportedTechnologies=BR/EDR\n" + "Trusted=true\n" + "Blocked=false\n" + "Services=00001124-0000-1000-8000-00805f9b34fb;\n" + "\n" + "[DeviceID]\n" + "Source=1\n" + "Vendor=1356\n" + "Product=" + std::to_string(pid) + "\n" + "Version=1\n"; +}; const std::string BLUEZ5_CACHE_ENTRY { @@ -360,11 +362,13 @@ psmove_port_get_host_bluetooth_address() } void -psmove_port_register_psmove(const char *addr, const char *host) +psmove_port_register_psmove(const char *addr, const char *host, PSMove_Model_Type model) { auto controller_addr = cstring_to_stdstring_free(_psmove_normalize_btaddr(addr, 0, ':')); auto host_addr = cstring_to_stdstring_free(_psmove_normalize_btaddr(host, 0, ':')); + unsigned short pid = (model == Model_ZCM2) ? PSMOVE_PS4_PID : PSMOVE_PID; + if (controller_addr.empty()) { LINUXPAIR_DEBUG("Cannot parse controller address: '%s'\n", addr); return; @@ -403,7 +407,7 @@ psmove_port_register_psmove(const char *addr, const char *host) } } - if (!linux_bluez5_update_file_content(bluetoothd, info_dir + "/info", BLUEZ5_INFO_ENTRY)) { + if (!linux_bluez5_update_file_content(bluetoothd, info_dir + "/info", BLUEZ5_INFO_ENTRY(pid))) { return; } diff --git a/src/platform/psmove_port_osx.mm b/src/platform/psmove_port_osx.mm index e8dedc16..2e2c206c 100644 --- a/src/platform/psmove_port_osx.mm +++ b/src/platform/psmove_port_osx.mm @@ -241,8 +241,10 @@ }; void -psmove_port_register_psmove(const char *addr, const char *host) +psmove_port_register_psmove(const char *addr, const char *host, PSMove_Model_Type model) { + // TODO: FIXME: If necessary, handle different controller models differently. + ScopedNSAutoreleasePool pool; std::string btaddr = cstring_to_stdstring_free(_psmove_normalize_btaddr(addr, 1, '-')); diff --git a/src/platform/psmove_port_windows.c b/src/platform/psmove_port_windows.c index f6a955a3..c3c6f93f 100644 --- a/src/platform/psmove_port_windows.c +++ b/src/platform/psmove_port_windows.c @@ -669,6 +669,8 @@ psmove_port_get_host_bluetooth_address() void psmove_port_register_psmove(const char *addr, const char *host) { + // TODO: FIXME: If necessary, handle different controller models differently. + // FIXME: Host is ignored for now HANDLE hRadio; diff --git a/src/psmove.c b/src/psmove.c index 1dd4aaea..0e9c0a15 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -212,6 +212,9 @@ struct _PSMove { PSMove_Data_LEDs leds; PSMove_Data_Input input; + /* Controller hardware model */ + enum PSMove_Model_Type model; + /* Save location for the serial number */ char *serial_number; @@ -427,7 +430,7 @@ psmove_count_connected() } PSMove * -psmove_connect_internal(const wchar_t *serial, const char *path, int id) +psmove_connect_internal(const wchar_t *serial, const char *path, int id, unsigned short pid) { char *tmp; @@ -499,6 +502,8 @@ psmove_connect_internal(const wchar_t *serial, const char *path, int id) /* Message type for LED set requests */ move->leds.type = PSMove_Req_SetLEDs; + move->model = (pid == PSMOVE_PS4_PID) ? Model_ZCM2 : Model_ZCM1; + /* Remember the ID/index */ move->id = id; @@ -694,6 +699,9 @@ psmove_connect_remote_by_id(int id, moved_client *client, int remote_id) /* Message type for LED set requests */ move->leds.type = PSMove_Req_SetLEDs; + // TODO: Add support for other models + move->model = Model_ZCM1; + /* Remember the ID/index */ move->id = id; @@ -820,7 +828,7 @@ psmove_connect_by_id(int id) if (strstr(cur_dev->path, "&col01#") != NULL) { if (count == id) { - move = psmove_connect_internal(cur_dev->serial_number, cur_dev->path, id); + move = psmove_connect_internal(cur_dev->serial_number, cur_dev->path, id, cur_dev->product_id); break; } } else { @@ -832,7 +840,7 @@ psmove_connect_by_id(int id) #else if (id < available) { cur_dev = devs_sorted[id]; - move = psmove_connect_internal(cur_dev->serial_number, cur_dev->path, id); + move = psmove_connect_internal(cur_dev->serial_number, cur_dev->path, id, cur_dev->product_id); } #endif @@ -1034,7 +1042,7 @@ psmove_pair(PSMove *move) char *addr = psmove_get_serial(move); - psmove_port_register_psmove(addr, host); + psmove_port_register_psmove(addr, host, move->model); free(addr); free(host); @@ -1043,13 +1051,13 @@ psmove_pair(PSMove *move) } enum PSMove_Bool -psmove_host_pair_custom(const char *addr) +psmove_host_pair_custom(const char *addr, enum PSMove_Model_Type model) { char *host = psmove_port_get_host_bluetooth_address(); psmove_return_val_if_fail(host != NULL, PSMove_False); - psmove_port_register_psmove(addr, host); + psmove_port_register_psmove(addr, host, model); free(host); @@ -1083,7 +1091,7 @@ psmove_pair_custom(PSMove *move, const char *new_host_string) char *addr = psmove_get_serial(move); char *host = _psmove_btaddr_to_string(new_host); - psmove_port_register_psmove(addr, host); + psmove_port_register_psmove(addr, host, move->model); free(addr); free(host); diff --git a/src/psmove_port.h b/src/psmove_port.h index ef996717..098b1e50 100644 --- a/src/psmove_port.h +++ b/src/psmove_port.h @@ -112,7 +112,7 @@ ADDCALL psmove_port_get_host_bluetooth_address(); * Add the PS Move Bluetooth controller address to the system database **/ ADDAPI void -ADDCALL psmove_port_register_psmove(const char *addr, const char *host); +ADDCALL psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Model_Type model); #ifdef __cplusplus } diff --git a/src/psmove_private.h b/src/psmove_private.h index e0596785..13c0c654 100644 --- a/src/psmove_private.h +++ b/src/psmove_private.h @@ -130,7 +130,7 @@ ADDCALL _psmove_read_data(PSMove *move, unsigned char *data, int length); * [PRIVATE API] Internal device open function (hidraw, Linux / for moved) **/ ADDAPI PSMove * -ADDCALL psmove_connect_internal(const wchar_t *serial, const char *path, int id); +ADDCALL psmove_connect_internal(const wchar_t *serial, const char *path, int id, unsigned short pid); /** * [PRIVATE API] Get device path of a controller (hidraw, Linux / for moved) diff --git a/src/psmoveapi.cpp b/src/psmoveapi.cpp index d3df06db..e69a97a6 100644 --- a/src/psmoveapi.cpp +++ b/src/psmoveapi.cpp @@ -299,7 +299,11 @@ PSMoveAPI::on_monitor_event(enum MonitorEvent event, enum MonitorEventDeviceType } } - PSMove *move = psmove_connect_internal(serial, path, -1); + // TODO: FIXME: This should use the device's actual USB product ID. + // HACK: We rely on this invalid PID being translated to a + // valid controller model (the old ZCM1, be default). + unsigned short pid = 0; + PSMove *move = psmove_connect_internal(serial, path, -1, pid); if (move == nullptr) { psmove_CRITICAL("Cannot open move for retrieving serial!"); return; diff --git a/src/utils/psmoveregister.c b/src/utils/psmoveregister.c index c90bc8b2..f7cbc447 100644 --- a/src/utils/psmoveregister.c +++ b/src/utils/psmoveregister.c @@ -38,12 +38,14 @@ #include "../psmove_private.h" #include "../psmove_port.h" +#define OPT_PS4 "--ps4" + int main(int argc, char *argv[]) { - if (argc != 2) { - fprintf(stderr, "Usage: %s [bluetooth-address]\n", argv[0]); + if (argc < 2) { + fprintf(stderr, "Usage: %s [%s] bluetooth-address\n", argv[0], OPT_PS4); return 1; } @@ -51,7 +53,15 @@ main(int argc, char *argv[]) return 1; } - if (psmove_host_pair_custom(argv[1])) { + char *bdaddr = argv[1]; + PSMove_Model_Type model = Model_ZCM1; + + if ((argc > 2) && (strcmp(argv[1], OPT_PS4) == 0)) { + bdaddr = argv[2]; + model = Model_ZCM2; + } + + if (psmove_host_pair_custom(bdaddr, model)) { printf("Paired\n"); } else { printf("Pairing failed\n"); From 459183f66e6c821f084ad42b4da96efe80014625 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 8 Jul 2018 19:46:22 +0200 Subject: [PATCH 05/17] Add BlueZ agent for registering PS4 Move controllers This agent simply answers any HCI PIN Code Request with the PIN code '0000'. --- contrib/.gitignore | 2 + contrib/bluezutils.py | 49 +++++++++++ contrib/pin-agent.py | 194 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 contrib/.gitignore create mode 100644 contrib/bluezutils.py create mode 100644 contrib/pin-agent.py diff --git a/contrib/.gitignore b/contrib/.gitignore new file mode 100644 index 00000000..2f78cf5b --- /dev/null +++ b/contrib/.gitignore @@ -0,0 +1,2 @@ +*.pyc + diff --git a/contrib/bluezutils.py b/contrib/bluezutils.py new file mode 100644 index 00000000..7d0b3132 --- /dev/null +++ b/contrib/bluezutils.py @@ -0,0 +1,49 @@ +# From https://git.kernel.org/pub/scm/bluetooth/bluez.git/plain/test/bluezutils.py + +import dbus + +SERVICE_NAME = "org.bluez" +ADAPTER_INTERFACE = SERVICE_NAME + ".Adapter1" +DEVICE_INTERFACE = SERVICE_NAME + ".Device1" + +def get_managed_objects(): + bus = dbus.SystemBus() + manager = dbus.Interface(bus.get_object("org.bluez", "/"), + "org.freedesktop.DBus.ObjectManager") + return manager.GetManagedObjects() + +def find_adapter(pattern=None): + return find_adapter_in_objects(get_managed_objects(), pattern) + +def find_adapter_in_objects(objects, pattern=None): + bus = dbus.SystemBus() + for path, ifaces in objects.items(): + adapter = ifaces.get(ADAPTER_INTERFACE) + if adapter is None: + continue + if not pattern or pattern == adapter["Address"] or \ + path.endswith(pattern): + obj = bus.get_object(SERVICE_NAME, path) + return dbus.Interface(obj, ADAPTER_INTERFACE) + raise Exception("Bluetooth adapter not found") + +def find_device(device_address, adapter_pattern=None): + return find_device_in_objects(get_managed_objects(), device_address, + adapter_pattern) + +def find_device_in_objects(objects, device_address, adapter_pattern=None): + bus = dbus.SystemBus() + path_prefix = "" + if adapter_pattern: + adapter = find_adapter_in_objects(objects, adapter_pattern) + path_prefix = adapter.object_path + for path, ifaces in objects.items(): + device = ifaces.get(DEVICE_INTERFACE) + if device is None: + continue + if (device["Address"] == device_address and + path.startswith(path_prefix)): + obj = bus.get_object(SERVICE_NAME, path) + return dbus.Interface(obj, DEVICE_INTERFACE) + + raise Exception("Bluetooth device not found") diff --git a/contrib/pin-agent.py b/contrib/pin-agent.py new file mode 100644 index 00000000..526dd2da --- /dev/null +++ b/contrib/pin-agent.py @@ -0,0 +1,194 @@ +#!/usr/bin/python + +# Registers a BlueZ D-Bus agent that automatically answers any PIN Code +# Request with PIN code '0000'. +# +# Adapted from https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test/simple-agent +# + + +from __future__ import absolute_import, print_function, unicode_literals + +from optparse import OptionParser +import sys +import dbus +import dbus.service +import dbus.mainloop.glib +try: + from gi.repository import GObject +except ImportError: + import gobject as GObject +import bluezutils + +BUS_NAME = 'org.bluez' +AGENT_INTERFACE = 'org.bluez.Agent1' +AGENT_PATH = "/test/agent" + +PIN_CODE = "0000" + +bus = None +device_obj = None +dev_path = None + +def ask(prompt): + try: + return raw_input(prompt) + except: + return input(prompt) + +def set_trusted(path): + props = dbus.Interface(bus.get_object("org.bluez", path), + "org.freedesktop.DBus.Properties") + props.Set("org.bluez.Device1", "Trusted", True) + +def dev_connect(path): + dev = dbus.Interface(bus.get_object("org.bluez", path), + "org.bluez.Device1") + dev.Connect() + +class Rejected(dbus.DBusException): + _dbus_error_name = "org.bluez.Error.Rejected" + +class Agent(dbus.service.Object): + exit_on_release = True + + def set_exit_on_release(self, exit_on_release): + self.exit_on_release = exit_on_release + + @dbus.service.method(AGENT_INTERFACE, + in_signature="", out_signature="") + def Release(self): + print("Release") + if self.exit_on_release: + mainloop.quit() + + @dbus.service.method(AGENT_INTERFACE, + in_signature="os", out_signature="") + def AuthorizeService(self, device, uuid): + print("AuthorizeService (%s, %s)" % (device, uuid)) + authorize = ask("Authorize connection (yes/no): ") + if (authorize == "yes"): + return + raise Rejected("Connection rejected by user") + + @dbus.service.method(AGENT_INTERFACE, + in_signature="o", out_signature="s") + def RequestPinCode(self, device): + print("RequestPinCode (%s)" % (device)) + set_trusted(device) + print("Sending PIN code '%s'" % (PIN_CODE)) + return PIN_CODE + + @dbus.service.method(AGENT_INTERFACE, + in_signature="o", out_signature="u") + def RequestPasskey(self, device): + print("RequestPasskey (%s)" % (device)) + set_trusted(device) + passkey = ask("Enter passkey: ") + return dbus.UInt32(passkey) + + @dbus.service.method(AGENT_INTERFACE, + in_signature="ouq", out_signature="") + def DisplayPasskey(self, device, passkey, entered): + print("DisplayPasskey (%s, %06u entered %u)" % + (device, passkey, entered)) + + @dbus.service.method(AGENT_INTERFACE, + in_signature="os", out_signature="") + def DisplayPinCode(self, device, pincode): + print("DisplayPinCode (%s, %s)" % (device, pincode)) + + @dbus.service.method(AGENT_INTERFACE, + in_signature="ou", out_signature="") + def RequestConfirmation(self, device, passkey): + print("RequestConfirmation (%s, %06d)" % (device, passkey)) + confirm = ask("Confirm passkey (yes/no): ") + if (confirm == "yes"): + set_trusted(device) + return + raise Rejected("Passkey doesn't match") + + @dbus.service.method(AGENT_INTERFACE, + in_signature="o", out_signature="") + def RequestAuthorization(self, device): + print("RequestAuthorization (%s)" % (device)) + auth = ask("Authorize? (yes/no): ") + if (auth == "yes"): + return + raise Rejected("Pairing rejected") + + @dbus.service.method(AGENT_INTERFACE, + in_signature="", out_signature="") + def Cancel(self): + print("Cancel") + +def pair_reply(): + print("Device paired") + set_trusted(dev_path) + dev_connect(dev_path) + mainloop.quit() + +def pair_error(error): + err_name = error.get_dbus_name() + if err_name == "org.freedesktop.DBus.Error.NoReply" and device_obj: + print("Timed out. Cancelling pairing") + device_obj.CancelPairing() + else: + print("Creating device failed: %s" % (error)) + + + mainloop.quit() + +if __name__ == '__main__': + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + bus = dbus.SystemBus() + + capability = "KeyboardDisplay" + + parser = OptionParser() + parser.add_option("-i", "--adapter", action="store", + type="string", + dest="adapter_pattern", + default=None) + parser.add_option("-c", "--capability", action="store", + type="string", dest="capability") + parser.add_option("-t", "--timeout", action="store", + type="int", dest="timeout", + default=60000) + (options, args) = parser.parse_args() + if options.capability: + capability = options.capability + + path = "/test/agent" + agent = Agent(bus, path) + + mainloop = GObject.MainLoop() + + obj = bus.get_object(BUS_NAME, "/org/bluez"); + manager = dbus.Interface(obj, "org.bluez.AgentManager1") + manager.RegisterAgent(path, capability) + + print("Agent registered. Now press the controller's PS button.") + + # Fix-up old style invocation (BlueZ 4) + if len(args) > 0 and args[0].startswith("hci"): + options.adapter_pattern = args[0] + del args[:1] + + if len(args) > 0: + device = bluezutils.find_device(args[0], + options.adapter_pattern) + dev_path = device.object_path + agent.set_exit_on_release(False) + device.Pair(reply_handler=pair_reply, error_handler=pair_error, + timeout=60000) + device_obj = device + else: + manager.RequestDefaultAgent(path) + + mainloop.run() + + #adapter.UnregisterAgent(path) + #print("Agent unregistered") + From 9a6fe1a352b779df0beedf5737a633b1180de507 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 8 Jul 2018 20:11:52 +0200 Subject: [PATCH 06/17] Properly decode accel/gyro values for PS4 Move controllers Those values are stored in the HID report as two's complement. Also, there are no longer values from two different half-frames. --- src/psmove.c | 79 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/src/psmove.c b/src/psmove.c index 0e9c0a15..3e17a014 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -1603,19 +1604,33 @@ psmove_get_accelerometer(PSMove *move, int *ax, int *ay, int *az) { psmove_return_if_fail(move != NULL); - if (ax != NULL) { - *ax = ((move->input.aXlow + move->input.aXlow2) + - ((move->input.aXhigh + move->input.aXhigh2) << 8)) / 2 - 0x8000; - } + if (move->model == Model_ZCM2) { + if (ax != NULL) { + *ax = (int16_t) (move->input.aXlow + (move->input.aXhigh << 8)); + } - if (ay != NULL) { - *ay = ((move->input.aYlow + move->input.aYlow2) + - ((move->input.aYhigh + move->input.aYhigh2) << 8)) / 2 - 0x8000; - } + if (ay != NULL) { + *ay = (int16_t) (move->input.aYlow + (move->input.aYhigh << 8)); + } - if (az != NULL) { - *az = ((move->input.aZlow + move->input.aZlow2) + - ((move->input.aZhigh + move->input.aZhigh2) << 8)) / 2 - 0x8000; + if (az != NULL) { + *az = (int16_t) (move->input.aZlow + (move->input.aZhigh << 8)); + } + } else { + if (ax != NULL) { + *ax = ((move->input.aXlow + move->input.aXlow2) + + ((move->input.aXhigh + move->input.aXhigh2) << 8)) / 2 - 0x8000; + } + + if (ay != NULL) { + *ay = ((move->input.aYlow + move->input.aYlow2) + + ((move->input.aYhigh + move->input.aYhigh2) << 8)) / 2 - 0x8000; + } + + if (az != NULL) { + *az = ((move->input.aZlow + move->input.aZlow2) + + ((move->input.aZhigh + move->input.aZhigh2) << 8)) / 2 - 0x8000; + } } } @@ -1624,20 +1639,34 @@ psmove_get_gyroscope(PSMove *move, int *gx, int *gy, int *gz) { psmove_return_if_fail(move != NULL); - if (gx != NULL) { - *gx = ((move->input.gXlow + move->input.gXlow2) + - ((move->input.gXhigh + move->input.gXhigh2) << 8)) / 2 - 0x8000; - } - - if (gy != NULL) { - *gy = ((move->input.gYlow + move->input.gYlow2) + - ((move->input.gYhigh + move->input.gYhigh2) << 8)) / 2 - 0x8000; - } - - if (gz != NULL) { - *gz = ((move->input.gZlow + move->input.gZlow2) + - ((move->input.gZhigh + move->input.gZhigh2) << 8)) / 2 - 0x8000; - } + if (move->model == Model_ZCM2) { + if (gx != NULL) { + *gx = (int16_t) (move->input.gXlow + (move->input.gXhigh << 8)); + } + + if (gy != NULL) { + *gy = (int16_t) (move->input.gYlow + (move->input.gYhigh << 8)); + } + + if (gz != NULL) { + *gz = (int16_t) (move->input.gZlow + (move->input.gZhigh << 8)); + } + } else { + if (gx != NULL) { + *gx = ((move->input.gXlow + move->input.gXlow2) + + ((move->input.gXhigh + move->input.gXhigh2) << 8)) / 2 - 0x8000; + } + + if (gy != NULL) { + *gy = ((move->input.gYlow + move->input.gYlow2) + + ((move->input.gYhigh + move->input.gYhigh2) << 8)) / 2 - 0x8000; + } + + if (gz != NULL) { + *gz = ((move->input.gZlow + move->input.gZlow2) + + ((move->input.gZhigh + move->input.gZhigh2) << 8)) / 2 - 0x8000; + } + } } void From 22453dfb168e374c59a96773016b84d72c9b18b2 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 8 Jul 2018 20:19:49 +0200 Subject: [PATCH 07/17] Return zeros for PS4 Move controller's magnetometer readings This model does not have any magnetometers. --- src/psmove.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/psmove.c b/src/psmove.c index 3e17a014..cf2237e0 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -1780,19 +1780,35 @@ psmove_get_magnetometer(PSMove *move, int *mx, int *my, int *mz) { psmove_return_if_fail(move != NULL); - if (mx != NULL) { - *mx = TWELVE_BIT_SIGNED(((move->input.templow_mXhigh & 0x0F) << 8) | - move->input.mXlow); - } + if (move->model == Model_ZCM2) { + // NOTE: This model does not have magnetometers - if (my != NULL) { - *my = TWELVE_BIT_SIGNED((move->input.mYhigh << 4) | - (move->input.mYlow_mZhigh & 0xF0) >> 4); - } + if (mx != NULL) { + *mx = 0; + } - if (mz != NULL) { - *mz = TWELVE_BIT_SIGNED(((move->input.mYlow_mZhigh & 0x0F) << 8) | - move->input.mZlow); + if (my != NULL) { + *my = 0; + } + + if (mz != NULL) { + *mz = 0; + } + } else { + if (mx != NULL) { + *mx = TWELVE_BIT_SIGNED(((move->input.templow_mXhigh & 0x0F) << 8) | + move->input.mXlow); + } + + if (my != NULL) { + *my = TWELVE_BIT_SIGNED((move->input.mYhigh << 4) | + (move->input.mYlow_mZhigh & 0xF0) >> 4); + } + + if (mz != NULL) { + *mz = TWELVE_BIT_SIGNED(((move->input.mYlow_mZhigh & 0x0F) << 8) | + move->input.mZlow); + } } } From c2db065607b957ffa9115d7e28a1f1c37a5564e5 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 8 Jul 2018 20:27:43 +0200 Subject: [PATCH 08/17] Fix trigger value for PS4 Move controllers There are no half-frames in the HID input report anymore. Instead, the second value reported for the trigger button seems to be a heavily low-pass filtered version of the first one. We simply return the first value for this new controller model. --- src/psmove.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/psmove.c b/src/psmove.c index cf2237e0..d7cfee76 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -1558,7 +1558,11 @@ psmove_get_trigger(PSMove *move) { psmove_return_val_if_fail(move != NULL, 0); - return (move->input.trigger + move->input.trigger2) / 2; + if (move->model == Model_ZCM2) { + return move->input.trigger; + } else { + return (move->input.trigger + move->input.trigger2) / 2; + } } void From 561f516673b5321a4f59f67bb5764a5d2555cdde Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Mon, 9 Jul 2018 09:46:42 +0200 Subject: [PATCH 09/17] Fix changed function signature on Windows --- src/platform/psmove_port_windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/psmove_port_windows.c b/src/platform/psmove_port_windows.c index c3c6f93f..4005c71b 100644 --- a/src/platform/psmove_port_windows.c +++ b/src/platform/psmove_port_windows.c @@ -667,7 +667,7 @@ psmove_port_get_host_bluetooth_address() } void -psmove_port_register_psmove(const char *addr, const char *host) +psmove_port_register_psmove(const char *addr, const char *host, PSMove_Model_Type model) { // TODO: FIXME: If necessary, handle different controller models differently. From 6198310202e90e376efc113982f8fd886319a4af Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Mon, 9 Jul 2018 10:01:32 +0200 Subject: [PATCH 10/17] Fix broken type in function declaration Weird, GCC on Linux did not even issue a warning ... --- src/platform/psmove_port_linux.cpp | 2 +- src/platform/psmove_port_osx.mm | 2 +- src/platform/psmove_port_windows.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform/psmove_port_linux.cpp b/src/platform/psmove_port_linux.cpp index fbe96ccb..ecfd55d0 100644 --- a/src/platform/psmove_port_linux.cpp +++ b/src/platform/psmove_port_linux.cpp @@ -362,7 +362,7 @@ psmove_port_get_host_bluetooth_address() } void -psmove_port_register_psmove(const char *addr, const char *host, PSMove_Model_Type model) +psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Model_Type model) { auto controller_addr = cstring_to_stdstring_free(_psmove_normalize_btaddr(addr, 0, ':')); auto host_addr = cstring_to_stdstring_free(_psmove_normalize_btaddr(host, 0, ':')); diff --git a/src/platform/psmove_port_osx.mm b/src/platform/psmove_port_osx.mm index 2e2c206c..db3cfc7c 100644 --- a/src/platform/psmove_port_osx.mm +++ b/src/platform/psmove_port_osx.mm @@ -241,7 +241,7 @@ }; void -psmove_port_register_psmove(const char *addr, const char *host, PSMove_Model_Type model) +psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Model_Type model) { // TODO: FIXME: If necessary, handle different controller models differently. diff --git a/src/platform/psmove_port_windows.c b/src/platform/psmove_port_windows.c index 4005c71b..591d7e1f 100644 --- a/src/platform/psmove_port_windows.c +++ b/src/platform/psmove_port_windows.c @@ -667,7 +667,7 @@ psmove_port_get_host_bluetooth_address() } void -psmove_port_register_psmove(const char *addr, const char *host, PSMove_Model_Type model) +psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Model_Type model) { // TODO: FIXME: If necessary, handle different controller models differently. From 11e1875ba53f95ee5587531b0da4a765fd3b84a8 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 22 Jul 2018 23:32:43 +0200 Subject: [PATCH 11/17] Fix indentation --- src/psmove.c | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/psmove.c b/src/psmove.c index d7cfee76..525c77fb 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -1644,33 +1644,33 @@ psmove_get_gyroscope(PSMove *move, int *gx, int *gy, int *gz) psmove_return_if_fail(move != NULL); if (move->model == Model_ZCM2) { - if (gx != NULL) { - *gx = (int16_t) (move->input.gXlow + (move->input.gXhigh << 8)); - } - - if (gy != NULL) { - *gy = (int16_t) (move->input.gYlow + (move->input.gYhigh << 8)); - } - - if (gz != NULL) { - *gz = (int16_t) (move->input.gZlow + (move->input.gZhigh << 8)); - } - } else { - if (gx != NULL) { - *gx = ((move->input.gXlow + move->input.gXlow2) + - ((move->input.gXhigh + move->input.gXhigh2) << 8)) / 2 - 0x8000; - } - - if (gy != NULL) { - *gy = ((move->input.gYlow + move->input.gYlow2) + - ((move->input.gYhigh + move->input.gYhigh2) << 8)) / 2 - 0x8000; - } - - if (gz != NULL) { - *gz = ((move->input.gZlow + move->input.gZlow2) + - ((move->input.gZhigh + move->input.gZhigh2) << 8)) / 2 - 0x8000; - } - } + if (gx != NULL) { + *gx = (int16_t) (move->input.gXlow + (move->input.gXhigh << 8)); + } + + if (gy != NULL) { + *gy = (int16_t) (move->input.gYlow + (move->input.gYhigh << 8)); + } + + if (gz != NULL) { + *gz = (int16_t) (move->input.gZlow + (move->input.gZhigh << 8)); + } + } else { + if (gx != NULL) { + *gx = ((move->input.gXlow + move->input.gXlow2) + + ((move->input.gXhigh + move->input.gXhigh2) << 8)) / 2 - 0x8000; + } + + if (gy != NULL) { + *gy = ((move->input.gYlow + move->input.gYlow2) + + ((move->input.gYhigh + move->input.gYhigh2) << 8)) / 2 - 0x8000; + } + + if (gz != NULL) { + *gz = ((move->input.gZlow + move->input.gZlow2) + + ((move->input.gZhigh + move->input.gZhigh2) << 8)) / 2 - 0x8000; + } + } } void From abd457e406d20a7650c08552654a38e28b6b89c2 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 22 Jul 2018 23:36:02 +0200 Subject: [PATCH 12/17] Replace macro with string variable --- src/utils/psmoveregister.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/psmoveregister.c b/src/utils/psmoveregister.c index f7cbc447..a34de335 100644 --- a/src/utils/psmoveregister.c +++ b/src/utils/psmoveregister.c @@ -38,7 +38,7 @@ #include "../psmove_private.h" #include "../psmove_port.h" -#define OPT_PS4 "--ps4" +static const char *OPT_PS4 = "--ps4"; int From 3a98873a81957c1f1e36e6b7f3c61df79a4e8dd7 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 22 Jul 2018 23:41:03 +0200 Subject: [PATCH 13/17] Fix freeing HID enumeration --- src/psmove.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psmove.c b/src/psmove.c index 525c77fb..672d6dfc 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -849,7 +849,7 @@ psmove_connect_by_id(int id) // free HID device enumerations for (i = 0; i < NUM_PSMOVE_PIDS; i++) { - devs = hid_enumerate(PSMOVE_VID, PSMOVE_PIDS[i]); + devs = move_hid_devices[i]; if (devs) { hid_free_enumeration(devs); } From 94cb319b35760d908d5f012bb6925cb27531adcd Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 22 Jul 2018 23:44:19 +0200 Subject: [PATCH 14/17] Fix typo in comments --- src/daemon/moved.cpp | 4 ++-- src/psmoveapi.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/daemon/moved.cpp b/src/daemon/moved.cpp index 4691a89f..1f8c02e4 100644 --- a/src/daemon/moved.cpp +++ b/src/daemon/moved.cpp @@ -102,7 +102,7 @@ on_monitor_update_moved(enum MonitorEvent event, if (device_type == EVENT_DEVICE_TYPE_USB) { // TODO: FIXME: This should use the device's actual USB product ID. // HACK: We rely on this invalid PID being translated to a - // valid controller model (the old ZCM1, be default). + // valid controller model (the old ZCM1, by default). unsigned short pid = 0; PSMove *move = psmove_connect_internal(serial, path, -1, pid); if (psmove_pair(move)) { @@ -311,7 +311,7 @@ psmove_dev::psmove_dev(move_daemon *moved, const char *path, const wchar_t *seri if (path != NULL) { // TODO: FIXME: This should use the device's actual USB product ID. // HACK: We rely on this invalid PID being translated to a - // valid controller model (the old ZCM1, be default). + // valid controller model (the old ZCM1, by default). unsigned short pid = 0; move = psmove_connect_internal((wchar_t *)serial, (char *)path, moved->count(), pid); } else { diff --git a/src/psmoveapi.cpp b/src/psmoveapi.cpp index e69a97a6..50a08c0c 100644 --- a/src/psmoveapi.cpp +++ b/src/psmoveapi.cpp @@ -301,7 +301,7 @@ PSMoveAPI::on_monitor_event(enum MonitorEvent event, enum MonitorEventDeviceType // TODO: FIXME: This should use the device's actual USB product ID. // HACK: We rely on this invalid PID being translated to a - // valid controller model (the old ZCM1, be default). + // valid controller model (the old ZCM1, by default). unsigned short pid = 0; PSMove *move = psmove_connect_internal(serial, path, -1, pid); if (move == nullptr) { From 5431ba7096a8cadf2647b11fe646478f1acea998 Mon Sep 17 00:00:00 2001 From: Alexander Nitsch Date: Sun, 22 Jul 2018 23:59:30 +0200 Subject: [PATCH 15/17] Revert public API changes to psmove_host_pair_custom() Instead, introduce a new function psmove_host_pair_custom_model() that accepts the controller hardware model as additional argument. This keeps the public API stable. --- include/psmove.h | 14 +++++++++++++- src/psmove.c | 10 +++++++++- src/utils/psmoveregister.c | 2 +- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/psmove.h b/include/psmove.h index 6292b9f2..88aaba49 100644 --- a/include/psmove.h +++ b/include/psmove.h @@ -423,10 +423,22 @@ ADDCALL psmove_pair(PSMove *move); * \brief Add an entry for a controller paired on another host. * * \param addr The Bluetooth address of the PS move to add + **/ +ADDAPI enum PSMove_Bool +ADDCALL psmove_host_pair_custom(const char *addr); + +/** + * \brief Add an entry for a controller paired on another host. + * + * This function behaves the same as psmove_host_pair_custom() but allows you + * to specify a controller hardware model. Use this to pair a PS4 Move Motion + * controller (model ZCM2). + * + * \param addr The Bluetooth address of the PS move to add * \param model The hardware model type of the controller **/ ADDAPI enum PSMove_Bool -ADDCALL psmove_host_pair_custom(const char *addr, enum PSMove_Model_Type model); +ADDCALL psmove_host_pair_custom_model(const char *addr, enum PSMove_Model_Type model); /** * \brief Pair a controller connected via USB to a specific address. diff --git a/src/psmove.c b/src/psmove.c index 672d6dfc..5c62927a 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -1052,7 +1052,15 @@ psmove_pair(PSMove *move) } enum PSMove_Bool -psmove_host_pair_custom(const char *addr, enum PSMove_Model_Type model) +psmove_host_pair_custom(const char *addr) +{ + // NOTE: We assume Move Motion controller model ZCM1 to be compatible with + // earlier version of the library that only supported that model. + return psmove_host_pair_custom_model(addr, Model_ZCM1); +} + +enum PSMove_Bool +psmove_host_pair_custom_model(const char *addr, enum PSMove_Model_Type model) { char *host = psmove_port_get_host_bluetooth_address(); diff --git a/src/utils/psmoveregister.c b/src/utils/psmoveregister.c index a34de335..82934374 100644 --- a/src/utils/psmoveregister.c +++ b/src/utils/psmoveregister.c @@ -61,7 +61,7 @@ main(int argc, char *argv[]) model = Model_ZCM2; } - if (psmove_host_pair_custom(bdaddr, model)) { + if (psmove_host_pair_custom_model(bdaddr, model)) { printf("Paired\n"); } else { printf("Pairing failed\n"); From d37fe084635ba2c39c225eab6ad37916e4f691a1 Mon Sep 17 00:00:00 2001 From: Thomas Perl Date: Fri, 27 Jul 2018 14:57:59 +0200 Subject: [PATCH 16/17] Fix psmoveregister command line parsing --- src/utils/psmoveregister.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/utils/psmoveregister.c b/src/utils/psmoveregister.c index 82934374..fb58487c 100644 --- a/src/utils/psmoveregister.c +++ b/src/utils/psmoveregister.c @@ -40,25 +40,38 @@ static const char *OPT_PS4 = "--ps4"; +static void +psmoveregister_usage(const char *progname) +{ + fprintf(stderr, "Usage: %s [%s] bluetooth-address\n", progname, OPT_PS4); +} int main(int argc, char *argv[]) { - if (argc < 2) { - fprintf(stderr, "Usage: %s [%s] bluetooth-address\n", argv[0], OPT_PS4); - return 1; - } - if (!psmove_port_check_pairing_permissions()) { return 1; } - char *bdaddr = argv[1]; + char *bdaddr = NULL; PSMove_Model_Type model = Model_ZCM1; - if ((argc > 2) && (strcmp(argv[1], OPT_PS4) == 0)) { - bdaddr = argv[2]; - model = Model_ZCM2; + for (int i=1; i Date: Fri, 27 Jul 2018 15:08:26 +0200 Subject: [PATCH 17/17] Add return value to psmove_port_register_psmove --- src/daemon/moved.cpp | 4 +++- src/platform/psmove_port_linux.cpp | 18 ++++++++++-------- src/platform/psmove_port_osx.mm | 20 +++++++++++++++----- src/platform/psmove_port_windows.c | 10 ++++++---- src/psmove.c | 12 ++++++------ src/psmove_port.h | 2 +- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/daemon/moved.cpp b/src/daemon/moved.cpp index 1f8c02e4..be901070 100644 --- a/src/daemon/moved.cpp +++ b/src/daemon/moved.cpp @@ -275,7 +275,9 @@ moved_server::handle_request() char *host = psmove_port_get_host_bluetooth_address(); // TODO: Add support for other models - psmove_port_register_psmove(addr, host, Model_ZCM1); + if (!psmove_port_register_psmove(addr, host, Model_ZCM1)) { + printf("Could not register PS Move Controller in the system.\n"); + } free(addr); free(host); diff --git a/src/platform/psmove_port_linux.cpp b/src/platform/psmove_port_linux.cpp index ecfd55d0..7aefe2ef 100644 --- a/src/platform/psmove_port_linux.cpp +++ b/src/platform/psmove_port_linux.cpp @@ -361,7 +361,7 @@ psmove_port_get_host_bluetooth_address() return result.empty() ? nullptr : strdup(result.c_str()); } -void +enum PSMove_Bool psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Model_Type model) { auto controller_addr = cstring_to_stdstring_free(_psmove_normalize_btaddr(addr, 0, ':')); @@ -371,18 +371,18 @@ psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Mode if (controller_addr.empty()) { LINUXPAIR_DEBUG("Cannot parse controller address: '%s'\n", addr); - return; + return PSMove_False; } if (host_addr.empty()) { LINUXPAIR_DEBUG("Cannot parse host address: '%s'\n", host); - return; + return PSMove_False; } std::string bluetooth_dir { "/var/lib/bluetooth/" + host_addr }; if (!directory_exists(bluetooth_dir)) { LINUXPAIR_DEBUG("Not a directory: %s\n", bluetooth_dir.c_str()); - return; + return PSMove_False; } BluetoothDaemon bluetoothd; @@ -393,7 +393,7 @@ psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Mode if (!make_directory(info_dir)) { LINUXPAIR_DEBUG("Cannot create directory: %s\n", info_dir.c_str()); - return; + return PSMove_False; } } @@ -403,15 +403,17 @@ psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Mode if (!make_directory(cache_dir)) { LINUXPAIR_DEBUG("Cannot create directory: %s\n", cache_dir.c_str()); - return; + return PSMove_False; } } if (!linux_bluez5_update_file_content(bluetoothd, info_dir + "/info", BLUEZ5_INFO_ENTRY(pid))) { - return; + return PSMove_False; } if (!linux_bluez5_update_file_content(bluetoothd, cache_dir + "/" + controller_addr, BLUEZ5_CACHE_ENTRY)) { - return; + return PSMove_False; } + + return PSMove_True; } diff --git a/src/platform/psmove_port_osx.mm b/src/platform/psmove_port_osx.mm index db3cfc7c..5d3e9014 100644 --- a/src/platform/psmove_port_osx.mm +++ b/src/platform/psmove_port_osx.mm @@ -233,28 +233,35 @@ std::string cstring_to_stdstring_free(char *cstring) { - std::string result = cstring; + std::string result = cstring ?: ""; free(cstring); return result; } }; -void +enum PSMove_Bool psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Model_Type model) { + enum PSMove_Bool result = PSMove_True; + // TODO: FIXME: If necessary, handle different controller models differently. ScopedNSAutoreleasePool pool; std::string btaddr = cstring_to_stdstring_free(_psmove_normalize_btaddr(addr, 1, '-')); + if (btaddr.length() == 0) { + OSXPAIR_DEBUG("Not a valid Bluetooth address: %s\n", addr); + return PSMove_False; + } + int minor_version = macosx_get_minor_version(); if (minor_version == -1) { OSXPAIR_DEBUG("Cannot detect Mac OS X version.\n"); - return; + return PSMove_False; } else if (minor_version < 7) { OSXPAIR_DEBUG("No need to add entry for OS X before 10.7.\n"); - return; + return PSMove_False; } else { OSXPAIR_DEBUG("Detected: Mac OS X 10.%d\n", minor_version); } @@ -264,7 +271,7 @@ if (macosx_blued_is_paired(btaddr)) { OSXPAIR_DEBUG("Entry for %s already present.\n", btaddr.c_str()); - return; + return PSMove_True; } if (minor_version < 10) @@ -291,6 +298,7 @@ OSXPAIR_DEBUG("Running: '%s'\n", command.c_str()); if (system(command.c_str()) != 0) { OSXPAIR_DEBUG("Could not run the command."); + result = PSMove_False; } if (minor_version < 10) @@ -299,6 +307,8 @@ // from a fresh process (e.g. like "blueutil 1") to switch Bluetooth on macosx_bluetooth_set_powered(1); } + + return result; } void diff --git a/src/platform/psmove_port_windows.c b/src/platform/psmove_port_windows.c index 591d7e1f..f8758046 100644 --- a/src/platform/psmove_port_windows.c +++ b/src/platform/psmove_port_windows.c @@ -666,7 +666,7 @@ psmove_port_get_host_bluetooth_address() return _psmove_btaddr_to_string(btaddr); } -void +enum PSMove_Bool psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Model_Type model) { // TODO: FIXME: If necessary, handle different controller models differently. @@ -676,7 +676,7 @@ psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Mode HANDLE hRadio; if (windows_get_first_bluetooth_radio(&hRadio) != 0 || !hRadio) { psmove_WARNING("Failed to find a Bluetooth radio"); - return; + return PSMove_False; } BLUETOOTH_RADIO_INFO radioInfo; @@ -685,11 +685,13 @@ psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Mode if (BluetoothGetRadioInfo(hRadio, &radioInfo) != ERROR_SUCCESS) { psmove_CRITICAL("BluetoothGetRadioInfo"); CloseHandle(hRadio); - return; + return PSMove_False; } - windows_register_psmove(addr, &radioInfo.address, hRadio); + int res = windows_register_psmove(addr, &radioInfo.address, hRadio); CloseHandle(hRadio); + + return (res == 0) ? PSMove_True : PSMove_False; } #if !defined(_MSC_VER) diff --git a/src/psmove.c b/src/psmove.c index 5c62927a..57de1ec3 100644 --- a/src/psmove.c +++ b/src/psmove.c @@ -1043,12 +1043,12 @@ psmove_pair(PSMove *move) char *addr = psmove_get_serial(move); - psmove_port_register_psmove(addr, host, move->model); + enum PSMove_Bool result = psmove_port_register_psmove(addr, host, move->model); free(addr); free(host); - return PSMove_True; + return result; } enum PSMove_Bool @@ -1066,11 +1066,11 @@ psmove_host_pair_custom_model(const char *addr, enum PSMove_Model_Type model) psmove_return_val_if_fail(host != NULL, PSMove_False); - psmove_port_register_psmove(addr, host, model); + enum PSMove_Bool result = psmove_port_register_psmove(addr, host, model); free(host); - return PSMove_True; + return result; } enum PSMove_Bool @@ -1100,12 +1100,12 @@ psmove_pair_custom(PSMove *move, const char *new_host_string) char *addr = psmove_get_serial(move); char *host = _psmove_btaddr_to_string(new_host); - psmove_port_register_psmove(addr, host, move->model); + enum PSMove_Bool result = psmove_port_register_psmove(addr, host, move->model); free(addr); free(host); - return PSMove_True; + return result; } enum PSMove_Connection_Type diff --git a/src/psmove_port.h b/src/psmove_port.h index 098b1e50..1b4f274d 100644 --- a/src/psmove_port.h +++ b/src/psmove_port.h @@ -111,7 +111,7 @@ ADDCALL psmove_port_get_host_bluetooth_address(); /** * Add the PS Move Bluetooth controller address to the system database **/ -ADDAPI void +ADDAPI enum PSMove_Bool ADDCALL psmove_port_register_psmove(const char *addr, const char *host, enum PSMove_Model_Type model); #ifdef __cplusplus