os_nix.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * wiiuse
  3. *
  4. * Written By:
  5. * Michael Laforest < para >
  6. * Email: < thepara (--AT--) g m a i l [--DOT--] com >
  7. *
  8. * Copyright 2006-2007
  9. *
  10. * This file is part of wiiuse.
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 3 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. *
  25. * $Header$
  26. *
  27. */
  28. /**
  29. * @file
  30. * @brief Handles device I/O for *nix.
  31. */
  32. #include "io.h"
  33. #include "events.h"
  34. #include "os.h"
  35. #ifdef WIIUSE_BLUEZ
  36. #include <bluetooth/bluetooth.h> /* for ba2str, str2ba */
  37. #include <bluetooth/hci.h> /* for inquiry_info */
  38. #include <bluetooth/hci_lib.h> /* for hci_get_route, hci_inquiry, etc */
  39. #include <bluetooth/l2cap.h> /* for sockaddr_l2 */
  40. #include <stdio.h> /* for perror */
  41. #include <string.h> /* for memset */
  42. #include <sys/socket.h> /* for connect, socket */
  43. #include <sys/time.h> /* for struct timeval */
  44. #include <unistd.h> /* for close, write */
  45. #include <errno.h>
  46. #include <stdbool.h>
  47. static int wiiuse_os_connect_single(struct wiimote_t* wm, char* address);
  48. int wiiuse_os_find(struct wiimote_t** wm, int max_wiimotes, int timeout) {
  49. int device_id;
  50. int device_sock;
  51. inquiry_info scan_info_arr[128];
  52. inquiry_info* scan_info = scan_info_arr;
  53. int found_devices;
  54. int found_wiimotes;
  55. int i = 0;
  56. /* reset all wiimote bluetooth device addresses */
  57. for (found_wiimotes = 0; found_wiimotes < max_wiimotes; ++found_wiimotes) {
  58. /* bacpy(&(wm[found_wiimotes]->bdaddr), BDADDR_ANY); */
  59. memset(&(wm[found_wiimotes]->bdaddr), 0, sizeof(bdaddr_t));
  60. }
  61. found_wiimotes = 0;
  62. /* get the id of the first bluetooth device. */
  63. device_id = hci_get_route(NULL);
  64. if (device_id < 0) {
  65. if (errno == ENODEV) {
  66. WIIUSE_ERROR("Could not detect a Bluetooth adapter!");
  67. } else {
  68. perror("hci_get_route");
  69. }
  70. return 0;
  71. }
  72. /* create a socket to the device */
  73. device_sock = hci_open_dev(device_id);
  74. if (device_sock < 0) {
  75. perror("hci_open_dev");
  76. return 0;
  77. }
  78. memset(&scan_info_arr, 0, sizeof(scan_info_arr));
  79. /* scan for bluetooth devices for 'timeout' seconds */
  80. found_devices = hci_inquiry(device_id, timeout, 128, NULL, &scan_info, IREQ_CACHE_FLUSH);
  81. if (found_devices < 0) {
  82. perror("hci_inquiry");
  83. return 0;
  84. }
  85. WIIUSE_INFO("Found %i bluetooth device(s).", found_devices);
  86. /* display discovered devices */
  87. for (i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i) {
  88. bool is_wiimote_regular = (scan_info[i].dev_class[0] == WM_DEV_CLASS_0) &&
  89. (scan_info[i].dev_class[1] == WM_DEV_CLASS_1) &&
  90. (scan_info[i].dev_class[2] == WM_DEV_CLASS_2);
  91. bool is_wiimote_plus = (scan_info[i].dev_class[0] == WM_PLUS_DEV_CLASS_0) &&
  92. (scan_info[i].dev_class[1] == WM_PLUS_DEV_CLASS_1) &&
  93. (scan_info[i].dev_class[2] == WM_PLUS_DEV_CLASS_2);
  94. if (is_wiimote_regular || is_wiimote_plus) {
  95. /* found a device */
  96. ba2str(&scan_info[i].bdaddr, wm[found_wiimotes]->bdaddr_str);
  97. const char* str_type;
  98. if(is_wiimote_regular)
  99. {
  100. wm[found_wiimotes]->type = WIIUSE_WIIMOTE_REGULAR;
  101. str_type = " (regular wiimote)";
  102. }
  103. else if(is_wiimote_plus)
  104. {
  105. wm[found_wiimotes]->type = WIIUSE_WIIMOTE_MOTION_PLUS_INSIDE;
  106. str_type = " (motion plus inside)";
  107. }
  108. WIIUSE_INFO("Found wiimote (type: %s) (%s) [id %i].", str_type, wm[found_wiimotes]->bdaddr_str, wm[found_wiimotes]->unid);
  109. wm[found_wiimotes]->bdaddr = scan_info[i].bdaddr;
  110. WIIMOTE_ENABLE_STATE(wm[found_wiimotes], WIIMOTE_STATE_DEV_FOUND);
  111. ++found_wiimotes;
  112. }
  113. }
  114. close(device_sock);
  115. return found_wiimotes;
  116. }
  117. /**
  118. * @see wiiuse_connect()
  119. * @see wiiuse_os_connect_single()
  120. */
  121. int wiiuse_os_connect(struct wiimote_t** wm, int wiimotes) {
  122. int connected = 0;
  123. int i = 0;
  124. for (; i < wiimotes; ++i) {
  125. if (!WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_DEV_FOUND))
  126. /* if the device address is not set, skip it */
  127. {
  128. continue;
  129. }
  130. if (wiiuse_os_connect_single(wm[i], NULL)) {
  131. ++connected;
  132. }
  133. }
  134. return connected;
  135. }
  136. /**
  137. * @brief Connect to a wiimote with a known address.
  138. *
  139. * @param wm Pointer to a wiimote_t structure.
  140. * @param address The address of the device to connect to.
  141. * If NULL, use the address in the struct set by wiiuse_os_find().
  142. *
  143. * @return 1 on success, 0 on failure
  144. */
  145. static int wiiuse_os_connect_single(struct wiimote_t* wm, char* address) {
  146. struct sockaddr_l2 addr;
  147. memset(&addr, 0, sizeof(addr));
  148. if (!wm || WIIMOTE_IS_CONNECTED(wm)) {
  149. return 0;
  150. }
  151. addr.l2_family = AF_BLUETOOTH;
  152. bdaddr_t *bdaddr = &wm->bdaddr;
  153. if (address)
  154. /* use provided address */
  155. {
  156. str2ba(address, &addr.l2_bdaddr);
  157. } else {
  158. /** @todo this line doesn't make sense
  159. bacmp(bdaddr, BDADDR_ANY);*/
  160. /* use address of device discovered */
  161. addr.l2_bdaddr = *bdaddr;
  162. }
  163. /*
  164. * OUTPUT CHANNEL
  165. */
  166. wm->out_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
  167. if (wm->out_sock == -1) {
  168. return 0;
  169. }
  170. addr.l2_psm = htobs(WM_OUTPUT_CHANNEL);
  171. /* connect to wiimote */
  172. if (connect(wm->out_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
  173. perror("connect() output sock");
  174. return 0;
  175. }
  176. /*
  177. * INPUT CHANNEL
  178. */
  179. wm->in_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
  180. if (wm->in_sock == -1) {
  181. close(wm->out_sock);
  182. wm->out_sock = -1;
  183. return 0;
  184. }
  185. addr.l2_psm = htobs(WM_INPUT_CHANNEL);
  186. /* connect to wiimote */
  187. if (connect(wm->in_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
  188. perror("connect() interrupt sock");
  189. close(wm->out_sock);
  190. wm->out_sock = -1;
  191. return 0;
  192. }
  193. WIIUSE_INFO("Connected to wiimote [id %i].", wm->unid);
  194. /* do the handshake */
  195. WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
  196. wiiuse_handshake(wm, NULL, 0);
  197. wiiuse_set_report_type(wm);
  198. return 1;
  199. }
  200. void wiiuse_os_disconnect(struct wiimote_t* wm) {
  201. if (!wm || WIIMOTE_IS_CONNECTED(wm)) {
  202. return;
  203. }
  204. close(wm->out_sock);
  205. close(wm->in_sock);
  206. wm->out_sock = -1;
  207. wm->in_sock = -1;
  208. wm->event = WIIUSE_NONE;
  209. WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
  210. WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE);
  211. }
  212. int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes) {
  213. int evnt;
  214. struct timeval tv;
  215. fd_set fds;
  216. int r;
  217. int i;
  218. byte read_buffer[MAX_PAYLOAD];
  219. int highest_fd = -1;
  220. evnt = 0;
  221. if (!wm) {
  222. return 0;
  223. }
  224. /* block select() for 1/2000th of a second */
  225. tv.tv_sec = 0;
  226. tv.tv_usec = 500;
  227. FD_ZERO(&fds);
  228. for (i = 0; i < wiimotes; ++i) {
  229. /* only poll it if it is connected */
  230. if (WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_CONNECTED)) {
  231. FD_SET(wm[i]->in_sock, &fds);
  232. /* find the highest fd of the connected wiimotes */
  233. if (wm[i]->in_sock > highest_fd) {
  234. highest_fd = wm[i]->in_sock;
  235. }
  236. }
  237. wm[i]->event = WIIUSE_NONE;
  238. }
  239. if (highest_fd == -1)
  240. /* nothing to poll */
  241. {
  242. return 0;
  243. }
  244. if (select(highest_fd + 1, &fds, NULL, NULL, &tv) == -1) {
  245. WIIUSE_ERROR("Unable to select() the wiimote interrupt socket(s).");
  246. perror("Error Details");
  247. return 0;
  248. }
  249. /* check each socket for an event */
  250. for (i = 0; i < wiimotes; ++i) {
  251. /* if this wiimote is not connected, skip it */
  252. if (!WIIMOTE_IS_CONNECTED(wm[i])) {
  253. continue;
  254. }
  255. if (FD_ISSET(wm[i]->in_sock, &fds)) {
  256. /* clear out the event buffer */
  257. memset(read_buffer, 0, sizeof(read_buffer));
  258. /* clear out any old read data */
  259. clear_dirty_reads(wm[i]);
  260. /* read the pending message into the buffer */
  261. r = wiiuse_os_read(wm[i], read_buffer, sizeof(read_buffer));
  262. if (r > 0) {
  263. /* propagate the event */
  264. propagate_event(wm[i], read_buffer[0], read_buffer + 1);
  265. evnt += (wm[i]->event != WIIUSE_NONE);
  266. }
  267. } else {
  268. /* send out any waiting writes */
  269. wiiuse_send_next_pending_write_request(wm[i]);
  270. idle_cycle(wm[i]);
  271. }
  272. }
  273. return evnt;
  274. }
  275. int wiiuse_os_read(struct wiimote_t* wm, byte* buf, int len) {
  276. int rc;
  277. int i;
  278. rc = read(wm->in_sock, buf, len);
  279. if (rc == -1) {
  280. /* error reading data */
  281. WIIUSE_ERROR("Receiving wiimote data (id %i).", wm->unid);
  282. perror("Error Details");
  283. if (errno == ENOTCONN) {
  284. /* this can happen if the bluetooth dongle is disconnected */
  285. WIIUSE_ERROR("Bluetooth appears to be disconnected. Wiimote unid %i will be disconnected.", wm->unid);
  286. wiiuse_os_disconnect(wm);
  287. wiiuse_disconnected(wm);
  288. }
  289. } else if (rc == 0) {
  290. /* remote disconnect */
  291. wiiuse_disconnected(wm);
  292. } else {
  293. /* read successful */
  294. /* on *nix we ignore the first byte */
  295. memmove(buf, buf + 1, len - 1);
  296. /* log the received data */
  297. #ifdef WITH_WIIUSE_DEBUG
  298. {
  299. int i;
  300. printf("[DEBUG] (id %i) RECV: (%.2x) ", wm->unid, buf[0]);
  301. for (i = 1; i < rc; i++) {
  302. printf("%.2x ", buf[i]);
  303. }
  304. printf("\n");
  305. }
  306. #endif
  307. }
  308. return rc;
  309. }
  310. int wiiuse_os_write(struct wiimote_t* wm, byte report_type, byte* buf, int len) {
  311. int rc;
  312. byte write_buffer[MAX_PAYLOAD];
  313. write_buffer[0] = WM_SET_REPORT | WM_BT_OUTPUT;
  314. write_buffer[1] = report_type;
  315. memcpy(write_buffer + 2, buf, len);
  316. rc = write(wm->out_sock, write_buffer, len + 2);
  317. if (rc < 0) {
  318. wiiuse_disconnected(wm);
  319. }
  320. return rc;
  321. }
  322. void wiiuse_init_platform_fields(struct wiimote_t* wm) {
  323. memset(&(wm->bdaddr), 0, sizeof(bdaddr_t)); /* = *BDADDR_ANY;*/
  324. wm->out_sock = -1;
  325. wm->in_sock = -1;
  326. }
  327. void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) {
  328. wm->out_sock = -1;
  329. wm->in_sock = -1;
  330. }
  331. #endif /* ifdef WIIUSE_BLUEZ */