| 
									
										
										
										
											2021-08-24 19:10:23 +07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * The MIT License (MIT) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2021, Ha Thach (tinyusb.org) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  |  * of this software and associated documentation files (the "Software"), to deal | 
					
						
							|  |  |  |  * in the Software without restriction, including without limitation the rights | 
					
						
							|  |  |  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
					
						
							|  |  |  |  * copies of the Software, and to permit persons to whom the Software is | 
					
						
							|  |  |  |  * furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in | 
					
						
							|  |  |  |  * all copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
					
						
							|  |  |  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
					
						
							|  |  |  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
					
						
							|  |  |  |  * THE SOFTWARE. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "bsp/board.h"
 | 
					
						
							|  |  |  | #include "tusb.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* From https://www.kernel.org/doc/html/latest/input/gamepad.html
 | 
					
						
							|  |  |  |           ____________________________              __ | 
					
						
							|  |  |  |          / [__ZL__]          [__ZR__] \               | | 
					
						
							|  |  |  |         / [__ TL __]        [__ TR __] \              | Front Triggers | 
					
						
							|  |  |  |      __/________________________________\__         __| | 
					
						
							|  |  |  |     /                                  _   \          | | 
					
						
							|  |  |  |    /      /\           __             (N)   \         | | 
					
						
							|  |  |  |   /       ||      __  |MO|  __     _       _ \        | Main Pad | 
					
						
							|  |  |  |  |    <===DP===> |SE|      |ST|   (W) -|- (E) |       | | 
					
						
							|  |  |  |   \       ||    ___          ___       _     /        | | 
					
						
							|  |  |  |   /\      \/   /   \        /   \     (S)   /\      __| | 
					
						
							|  |  |  |  /  \________ | LS  | ____ |  RS | ________/  \       | | 
					
						
							|  |  |  | |         /  \ \___/ /    \ \___/ /  \         |      | Control Sticks | 
					
						
							|  |  |  | |        /    \_____/      \_____/    \        |    __| | 
					
						
							|  |  |  | |       /                              \       | | 
					
						
							|  |  |  |  \_____/                                \_____/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      |________|______|    |______|___________| | 
					
						
							|  |  |  |        D-Pad    Left       Right   Action Pad | 
					
						
							|  |  |  |                Stick       Stick | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                  |_____________| | 
					
						
							|  |  |  |                     Menu Pad | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Most gamepads have the following features: | 
					
						
							|  |  |  |   - Action-Pad 4 buttons in diamonds-shape (on the right side) NORTH, SOUTH, WEST and EAST. | 
					
						
							|  |  |  |   - D-Pad (Direction-pad) 4 buttons (on the left side) that point up, down, left and right. | 
					
						
							|  |  |  |   - Menu-Pad Different constellations, but most-times 2 buttons: SELECT - START. | 
					
						
							|  |  |  |   - Analog-Sticks provide freely moveable sticks to control directions, Analog-sticks may also | 
					
						
							|  |  |  |   provide a digital button if you press them. | 
					
						
							|  |  |  |   - Triggers are located on the upper-side of the pad in vertical direction. The upper buttons | 
					
						
							|  |  |  |   are normally named Left- and Right-Triggers, the lower buttons Z-Left and Z-Right. | 
					
						
							|  |  |  |   - Rumble Many devices provide force-feedback features. But are mostly just simple rumble motors. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Sony DS4 report layout detail https://www.psdevwiki.com/ps4/DS4-USB
 | 
					
						
							|  |  |  | typedef struct TU_ATTR_PACKED | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-24 21:34:51 +07:00
										 |  |  |   uint8_t x, y, z, rz; // joystick
 | 
					
						
							| 
									
										
										
										
											2021-08-24 19:10:23 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   struct { | 
					
						
							|  |  |  |     uint8_t dpad     : 4; // (hat format, 0x08 is released, 0=N, 1=NE, 2=E, 3=SE, 4=S, 5=SW, 6=W, 7=NW)
 | 
					
						
							|  |  |  |     uint8_t square   : 1; // west
 | 
					
						
							|  |  |  |     uint8_t cross    : 1; // south
 | 
					
						
							|  |  |  |     uint8_t circle   : 1; // east
 | 
					
						
							|  |  |  |     uint8_t triangle : 1; // north
 | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   struct { | 
					
						
							|  |  |  |     uint8_t l1     : 1; | 
					
						
							|  |  |  |     uint8_t r1     : 1; | 
					
						
							|  |  |  |     uint8_t l2     : 1; | 
					
						
							|  |  |  |     uint8_t r2     : 1; | 
					
						
							|  |  |  |     uint8_t share  : 1; | 
					
						
							|  |  |  |     uint8_t option : 1; | 
					
						
							|  |  |  |     uint8_t l3     : 1; | 
					
						
							|  |  |  |     uint8_t r3     : 1; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   struct { | 
					
						
							|  |  |  |     uint8_t ps      : 1; // playstation button
 | 
					
						
							|  |  |  |     uint8_t tpad    : 1; // track pad click
 | 
					
						
							|  |  |  |     uint8_t counter : 6; // +1 each report
 | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // comment out since not used by this example
 | 
					
						
							|  |  |  |   // uint8_t l2_trigger; // 0 released, 0xff fully pressed
 | 
					
						
							|  |  |  |   // uint8_t r2_trigger; // as above
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //  uint16_t timestamp;
 | 
					
						
							|  |  |  |   //  uint8_t  battery;
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   //  int16_t gyro[3];  // x, y, z;
 | 
					
						
							|  |  |  |   //  int16_t accel[3]; // x, y, z
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // there is still lots more info
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } sony_ds4_report_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // check if device is Sony DualShock 4
 | 
					
						
							|  |  |  | static inline bool is_sony_ds4(uint8_t dev_addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   uint16_t vid, pid; | 
					
						
							|  |  |  |   tuh_vid_pid_get(dev_addr, &vid, &pid); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-06 19:40:14 +02:00
										 |  |  |   return ( (vid == 0x054c && (pid == 0x09cc || pid == 0x05c4)) // Sony DualShock4 
 | 
					
						
							|  |  |  |            || (vid == 0x0f0d && pid == 0x005e)                 // Hori FC4 
 | 
					
						
							| 
									
										
										
										
											2021-09-07 21:13:34 -04:00
										 |  |  |            || (vid == 0x0f0d && pid == 0x00ee)                 // Hori PS4 Mini (PS4-099U) 
 | 
					
						
							| 
									
										
										
										
											2021-09-06 19:41:09 +02:00
										 |  |  |            || (vid == 0x1f4f && pid == 0x1002)                 // ASW GG xrd controller
 | 
					
						
							| 
									
										
										
										
											2021-09-06 19:40:14 +02:00
										 |  |  |          ); | 
					
						
							| 
									
										
										
										
											2021-08-24 19:10:23 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // MACRO TYPEDEF CONSTANT ENUM DECLARATION
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void hid_app_task(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // nothing to do
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // TinyUSB Callbacks
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Invoked when device with hid interface is mounted
 | 
					
						
							|  |  |  | // Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
 | 
					
						
							|  |  |  | // can be used to parse common/simple enough descriptor.
 | 
					
						
							|  |  |  | // Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
 | 
					
						
							|  |  |  | // therefore report_desc = NULL, desc_len = 0
 | 
					
						
							|  |  |  | void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-11-29 00:45:57 +09:00
										 |  |  |   (void)desc_report; | 
					
						
							|  |  |  |   (void)desc_len; | 
					
						
							| 
									
										
										
										
											2021-08-24 19:10:23 +07:00
										 |  |  |   uint16_t vid, pid; | 
					
						
							|  |  |  |   tuh_vid_pid_get(dev_addr, &vid, &pid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance); | 
					
						
							|  |  |  |   printf("VID = %04x, PID = %04x\r\n", vid, pid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Sony DualShock 4 [CUH-ZCT2x]
 | 
					
						
							|  |  |  |   if ( is_sony_ds4(dev_addr) ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // request to receive report
 | 
					
						
							|  |  |  |     // tuh_hid_report_received_cb() will be invoked when report is available
 | 
					
						
							|  |  |  |     if ( !tuh_hid_receive_report(dev_addr, instance) ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       printf("Error: cannot request to receive report\r\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Invoked when device with hid interface is un-mounted
 | 
					
						
							|  |  |  | void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // check if different than 2
 | 
					
						
							| 
									
										
										
										
											2021-08-24 21:34:51 +07:00
										 |  |  | bool diff_than_2(uint8_t x, uint8_t y) | 
					
						
							| 
									
										
										
										
											2021-08-24 19:10:23 +07:00
										 |  |  | { | 
					
						
							|  |  |  |   return (x - y > 2) || (y - x > 2); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // check if 2 reports are different enough
 | 
					
						
							|  |  |  | bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   bool result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // x, y, z, rz must different than 2 to be counted
 | 
					
						
							|  |  |  |   result = diff_than_2(rpt1->x, rpt2->x) || diff_than_2(rpt1->y , rpt2->y ) || | 
					
						
							|  |  |  |            diff_than_2(rpt1->z, rpt2->z) || diff_than_2(rpt1->rz, rpt2->rz); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // check the reset with mem compare
 | 
					
						
							|  |  |  |   result |= memcmp(&rpt1->rz + 1, &rpt2->rz + 1, sizeof(sony_ds4_report_t)-4); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void process_sony_ds4(uint8_t const* report, uint16_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   const char* dpad_str[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "none" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // previous report used to compare for changes
 | 
					
						
							|  |  |  |   static sony_ds4_report_t prev_report = { 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint8_t const report_id = report[0]; | 
					
						
							|  |  |  |   report++; | 
					
						
							|  |  |  |   len--; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // all buttons state is stored in ID 1
 | 
					
						
							|  |  |  |   if (report_id == 1) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     sony_ds4_report_t ds4_report; | 
					
						
							|  |  |  |     memcpy(&ds4_report, report, sizeof(ds4_report)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // counter is +1, assign to make it easier to compare 2 report
 | 
					
						
							|  |  |  |     prev_report.counter = ds4_report.counter; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // only print if changes since it is polled ~ 5ms
 | 
					
						
							|  |  |  |     // Since count+1 after each report and  x, y, z, rz fluctuate within 1 or 2
 | 
					
						
							|  |  |  |     // We need more than memcmp to check if report is different enough
 | 
					
						
							|  |  |  |     if ( diff_report(&prev_report, &ds4_report) ) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-24 21:34:51 +07:00
										 |  |  |       printf("(x, y, z, rz) = (%u, %u, %u, %u)\r\n", ds4_report.x, ds4_report.y, ds4_report.z, ds4_report.rz); | 
					
						
							| 
									
										
										
										
											2021-08-24 19:10:23 +07:00
										 |  |  |       printf("DPad = %s ", dpad_str[ds4_report.dpad]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (ds4_report.square   ) printf("Square "); | 
					
						
							|  |  |  |       if (ds4_report.cross    ) printf("Cross "); | 
					
						
							|  |  |  |       if (ds4_report.circle   ) printf("Circle "); | 
					
						
							|  |  |  |       if (ds4_report.triangle ) printf("Triangle "); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-24 21:34:51 +07:00
										 |  |  |       if (ds4_report.l1       ) printf("L1 "); | 
					
						
							|  |  |  |       if (ds4_report.r1       ) printf("R1 "); | 
					
						
							|  |  |  |       if (ds4_report.l2       ) printf("L2 "); | 
					
						
							|  |  |  |       if (ds4_report.r2       ) printf("R2 "); | 
					
						
							| 
									
										
										
										
											2021-08-24 19:10:23 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-24 21:34:51 +07:00
										 |  |  |       if (ds4_report.share    ) printf("Share "); | 
					
						
							|  |  |  |       if (ds4_report.option   ) printf("Option "); | 
					
						
							|  |  |  |       if (ds4_report.l3       ) printf("L3 "); | 
					
						
							|  |  |  |       if (ds4_report.r3       ) printf("R3 "); | 
					
						
							| 
									
										
										
										
											2021-08-24 19:10:23 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (ds4_report.ps       ) printf("PS "); | 
					
						
							|  |  |  |       if (ds4_report.tpad     ) printf("TPad "); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       printf("\r\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     prev_report = ds4_report; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Invoked when received report from device via interrupt endpoint
 | 
					
						
							|  |  |  | void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if ( is_sony_ds4(dev_addr) ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     process_sony_ds4(report, len); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // continue to request to receive report
 | 
					
						
							|  |  |  |   if ( !tuh_hid_receive_report(dev_addr, instance) ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     printf("Error: cannot request to receive report\r\n"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |