├── BlueRetro_Latency_Testing
├── temp.txt
└── README.md
├── platformio.ini
├── README.md
├── LightWing
└── main.cpp
├── HeavyWing
└── main.cpp
└── main.cpp
/BlueRetro_Latency_Testing/temp.txt:
--------------------------------------------------------------------------------
1 | test garbage
2 |
--------------------------------------------------------------------------------
/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [env:featheresp32]
12 | platform = espressif32
13 | board = featheresp32
14 | framework = arduino
15 | lib_deps =
16 | lemmingdev/ESP32-BLE-Gamepad@^0.5.1
17 | h2zero/NimBLE-Arduino@^1.4.0
18 | adafruit/Adafruit SSD1306@^2.5.4
19 | adafruit/Adafruit GFX Library@^1.11.2
20 | adafruit/Adafruit Unified Sensor@^1.1.5
21 | arduino-libraries/Bridge@^1.7.0
22 | adafruit/Adafruit MPU6050@^2.2.1
23 | monitor_speed = 115200
24 | monitor_filters = esp32_exception_decoder
25 |
--------------------------------------------------------------------------------
/BlueRetro_Latency_Testing/README.md:
--------------------------------------------------------------------------------
1 | # This is currently under construction.
2 |
3 | # Forward (Rant)
4 | If you are chasing low latency controllers and have never tested your display lag, you are approaching this *completely backwards*. If you are trying to blame controller latency before video as the culprit for how poorly you play games, reconsider. LAG is cumulative from input to output as far as your perception is concerned.
5 |
6 | Some of the better projectors for example alone add 30-70ms of lag. It's not uncommon to see with a series of connected devices in path 40-60ms before hitting your "2ms" LCD. Even your LCD is unlikely to perform at advertised speeds outside of VERY specific configurations. Wrong setting, add 18+ms. That's omitting any upscaler, AV Reciver in the middle, media converters, hdmi switches, etc - each of which may have setting based penalties.
7 |
8 | [RetroRGB](https://www.retrorgb.com/) has done extensive testing and how-to videos on the subject.
9 |
10 |
11 | # Controller Latency Testing in General
12 | Before we dive into the BLEGamepad/BlueRetro stuff, it's useful to understand how this testing is done in the wild elsewhere. Consistency is important across numerous controllers and setups. The best place to start is with the MiSTER.
13 |
14 | ## What you need:
15 | - [x] A controller - This acts as the "Transmitter" for the keypress
16 |
17 | - [x] Arduino Pro Micro - This performs time based calculation for Press->Recieve
18 |
19 | - [x] Your reciver - This is the "Receiving" device
20 | - For Mister this is via a custom USB Cable
21 | - It's BlueRetro for Bluetooth Controllers
22 |
23 | ## Detailed guide on how latency testing is performed on the Mister Platform:
24 | https://www.cathoderayblog.com/lag-test-your-controller-mister-fpga-input-latency-tester/
25 |
26 | I strongly advise taking a look over the content above as it will make everything from here much easier to understand. There are also a fair amount of videos floating around about this. Effectively you're using an arduino to "press" a button, and then another pin which will detect how fast that button is recieved on the other end. The arduino acts as a timer to count the time from when the press is sent to the time it is received and starts the next loop. After *10,000+* itterations, you have a good average input latency.
27 |
28 | ## The BIG Mister Controller Latency List:
29 | https://rpubs.com/misteraddons/inputlatency
30 |
31 | This is a list of controller input latency tests providing a useful comparison across a wide array of controllers as to what is "low latency", whats "Normal" and what is unbearably slow.
32 |
33 |
34 | # Latency Testing with [BlueRetro](https://github.com/darthcloud/BlueRetro)
35 | Darthcloud has included in BlueRetro a method to perform testing with the same arduino code that Mister uses. In brief you have to use the correct firmware, set the correct profile, and then use the right GPIO pin to connect to your arduino. You can read some more on this from his dev journal [here](https://hackaday.io/project/170365-blueretro/log/187443-2020-12-26-update-latency-tests-release-v010).
36 |
37 | There are some caveats you should be aware of I have spent *many* hours beating my head on a desk over.
38 |
39 | - [x] You **MUST** use the "parallel_1P_external.bin" when flashing firmware (Any firmware release version)
40 | - Console specific or embedded firmwares wont work
41 | - DO NOT connect your BR reciever to a console (Use **ONLY** external power)
42 |
43 | - [x] Before connecting your controller you **MUST** enable the "Latency Test" profile
44 | - If you fail to do this before connecting the controller you will have to power off the controller and reset blueretro or wait some time
45 | - Note: This often does not survive power down so confirm each time you need to power the BR adapter up again
46 |
47 | - [x] You **MUST** have access to GPIO26 on your BlueRetro testing device.
48 | - This could be risky if you only have console BR specific versions that require modification for output pin and the external power (eg. Pre-built N64 Adapter)
49 |
50 | - [x] You **MUST** have access to the PCB of your controller to solder on a wire for arduino to "press" your testing button
51 | - This typically requires modification to your controller PCB, like scraping away the coating to hit a copper trace.
52 | - This is also why my 3D Controller Lightwing PCBs have a dedicated pin on them to avoid damage.
53 | - Some controllers (including the Saturn 3D Pad) require a specific voltage (not just ground) so you may need to identify expected resistance
54 |
55 |
56 | # Latency Testing with [ESP32-BLE-Gamepad](https://github.com/lemmingDev/ESP32-BLE-Gamepad)
57 | ESP32-BLE-Gamepad does not contain any "specific" latency testing function. For testing you simply define a button that works when pulled low and to connect it to the correct controller facing arduino pin. In the code linked this pin should connect to arduino pin 5.
58 | - A lesson learned here is to avoid sending a Button ID/Number used elsewhere in code as it will self cancel in your initial loop not being detected **OR** make sure your code contains a check for **all** places that should use the pin and send the update accordingly.
59 |
60 | Defining a latency pin code example:
61 | ```
62 | if (digitalRead(latPin) == LOW) { //when arduino pulls this pin low send button press
63 | bleGamepad.press(BUTTON_1);
64 | } else {
65 | bleGamepad.release(BUTTON_1);
66 | }
67 | ```
68 |
69 | # Latency test your ESP32-BLE-Gamepad controller with BlueRetro
70 | I have used "BR" in place of BlueRetro below
71 |
72 | ### The Arduino Pro Micro
73 | 1. Flash your Arduino with the [latency test code](https://github.com/misteraddons/inputlatency/blob/main/arduino/MiSTer_USB_Latency_Test_Lemonici/MiSTer_USB_Latency_Test_Lemonici.ino)
74 |
75 | 2. Unplug your Arduino
76 |
77 | ### The Controller
78 | 3. Upload your ESP32-BLE-Gamepad code to your controller
79 |
80 | 4. Turn the controller OFF
81 |
82 | 5. Solder a wire to your controller pin to use for testing
83 |
84 | 6. Connect the wire soldered to the controller to Arduino Pin 5
85 |
86 | ### BlueRetro
87 | 7. [Flash the "parallel_1P_external.bin"](https://github.com/darthcloud/BlueRetro/wiki/BlueRetro-DIY-Build-Instructions) to your BlueRetro reciever and power cycle it
88 |
89 | 8. Connect GPIO26 (some boards may show as IO26) on BR to Pin 2 of the Arduino
90 |
91 | 9. Using **Chrome Browser** [connect to BR over bluetooth](https://hackaday.io/project/170365-blueretro/log/180020-web-bluetooth-ble-configuration-interface) and set the mapping profile to "Latency Test" and click save
92 | - Note: There is a "Test" profile in the second box - do not use this.
93 |
94 | - Example of the correct setting:
95 | 
96 |
97 | ### Start Latency Testing
98 | 10. Connect to the serial console of your arduino com port (115200 - 8 n 1)
99 | - Failure to connect to serial will not allow the code to start running
100 |
101 | 11. Power on your controller
102 |
103 | 12. Check your Serial console to the arduino and confirm it is incrimenting. If so Allow 10k+ itterations to complete to get your latency data.
104 | Example of the blinking you should see when testing is working correctly. Note, I you will only see 1 blink (on arduino) vs my install.
105 | Seizure Warning: 
106 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BLE-3D #
2 | Sega Saturn 3D Controller Bluetooth(BLE) Adapter
3 |
4 | # **What does it do?** #
5 | - This is an open source and completely solderless adapter for the Sega Saturn 3D Controller that converts it to a Bluetooth(BLE) HID Gamepad.
6 | - The end result demonstrates a battery powered and solderless adapter that allows you to use one of the best controllers ever made to date across numerous consoles
7 |
8 | ### Highlights ###
9 | - **Zero modifications to the factory controller** are neccesary to build, test, or play with this adapter.
10 | - Both Analog, and Digital mode (switch on controller) are fully supported
11 | - Want to revert back to OE? Simply plug the OE cable back in.
12 | - Latency testing pin on-pcb offers consistent and reproducible testing across code changes and development
13 |
14 | ### Lowlights ###
15 | - This isn't a "retail ready product", it's a proof of concept
16 | - No case for this has been published yet (bare pcb)
17 | - Power circuit has a couple issues. More details in Caveats section
18 |
19 |
20 | # **Compatibility** #
21 | This is an area I'm extremely proud of as of writing the BLE3D is known to work with:
22 | - Windows, Linux, and Steamdeck
23 | - ALL supported [Blueretro](https://github.com/darthcloud/BlueRetro) consoles
24 | - That means the 3D is now available on (in no particular order)
25 | - NeoGeo, Supergun, JAMMA
26 | - Atari 2600/7800, Master System
27 | - NES, PCE / TG16, Mega Drive / Genesis, SNES
28 | - CD-i, 3DO, Jaguar, Saturn, PSX, PC-FX,
29 | - JVS (Arcade), Virtual Boy, N64, Dreamcast, PS2, GameCube & Wii
30 | - I'm sure I'm missing a handful
31 |
32 | - Note: the analog pad/triggers support are per console, there is no 'digital emulation' on the analog stick.
33 |
34 |
35 | # **Background** #
36 | For years I've dreamed of a wireless Sega Saturn 3d Pad, just like the patents intended.
37 |
38 | - [US Patent Number US 7488,254 B2](https://patentimages.storage.googleapis.com/a2/97/47/e77a8c63165461/US7488254.pdf)
39 | - [US Patent Number Des. 409, 149](https://patentimages.storage.googleapis.com/3d/96/ad/edd675699738cf/USD409149.pdf)
40 | - [European Patent Number EP 1 332 778 B1](https://patentimages.storage.googleapis.com/ed/ba/17/c22422d5d3cc47/EP1332778B1.pdf)
41 | 
42 |
43 | Fast forward many years, I stumbled across some work [Hexfreq](https://twitter.com/hexfreq) was doing with arduino and asked if I could take a look at the code. The rest is history.
44 | From there [Humble Bazooka](https://twitter.com/humblebazooka) and I have spent countless hours to make sure this was a reality. I'd be remissed to leave out [darthcloud](https://twitter.com/darthcloud64) has also been an immense help along the way.
45 |
46 | # **PCBs** #
47 | - There are 2 publicly available DIY pcb's for "dev kits".
48 | - There are various issues or design misses with both pcbs
49 | - They aren't intended for retail use, but you can build one yourself **today**.
50 | - Beveling the controller facing pins is advised
51 |
52 | ## **LightWing** ##
53 | - This is a 'new' revision of the BLE-Saturn-3D that focuses on core functionality. This was optimized as the low cost option for home builders. At current, this is the advised version to use until development can progress farther on the extra features of the HeavyWing
54 | - PCB: https://oshpark.com/shared_projects/7RqwDWJT
55 |
56 |
57 | ## **HeavyWing** ##
58 | - The original PCB. Take the above patents put them in a blender. It adds LCD Support, Motion Controls & Rumble. You can use the LightWing code (better performance) on a Heavywing PCB but will need to change some pin mappings.
59 | - PCB: https://oshpark.com/shared_projects/ki7HbZV4
60 |
61 |
62 | # **BOM** #
63 | ## LightWing ###
64 | - 1x [LightWing PCB](https://oshpark.com/shared_projects/7RqwDWJT)
65 | - 1x [Adafruit Feather Huzzah32](https://www.adafruit.com/product/3405)
66 | - 1x Battery
67 |
68 |
69 | ## HeavyWing ##
70 | - 1x [HeavyWing PCB](https://oshpark.com/shared_projects/ki7HbZV4)
71 | - 1x [Adafruit Feather Huzzah32](https://www.adafruit.com/product/3405)
72 | - 1x [HiLetgo GY-521 AKA MPU-6050 Tilt Sensor](http://hiletgo.com/ProductDetail/2157948.html)* (optional - while it does "work" the kalman filter needs some rework. Must support 3.3v, some are 5v only)
73 | - 1x OLED 128X64 SSD1306 (optional)
74 | - 1x 3.3v Rumble Motor* (optional - this circuit is not populated on the PCB currently)
75 | - 1x Battery
76 |
77 |
78 |
79 | # **Assembly** #
80 | - Assembly is straightforward, it's just a PCB sandwhich and some solder
81 | - Orientation might be counter intuitive
82 |
83 | ### **LightWing - Assembly** ###
84 | - When you build this lay Segata Face-Down, then set the Feather through the holes with the ESP, USB, and Battery plug facing you
85 | - This provies some additional space for the battery directly under the PCB which would closet match the original patent docs visually
86 |
87 |
88 | ### **LightWing - Installation** ###
89 | - Sega Logo and Button Face top
90 | - Segata faces triggers or back of controller
91 |
92 |
93 | ### **HeavyWing - Assembly** ###
94 | - *Pictures to be uploaded soon*
95 |
96 |
97 | # **Before you compile the code** #
98 | - [PlatformIO installed in VScode](https://docs.platformio.org/en/stable/tutorials/espressif32/arduino_debugging_unit_testing.html), the [platformio.ini](https://github.com/GamingNJncos/BLE-3D-Saturn-Public/blob/main/platformio.ini), and the main.cpp for the Lightwing or the Heavywing
99 | - This has not been tested with Arduino IDE extensively but should compile fine however extremely slow
100 | - If you are mixing and matching LightWing code with the HeavyWing PCB, make sure you change the pinmapping.
101 | - This is well documented in the code if you jump to "Pinmappings for your PCB version"
102 |
103 | ## Powering the Device ##
104 | This is direct from the [Adafruit Documentation](https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/power-management)
105 | - There's two ways to power a Feather:
106 | - **You can connect with a USB cable** (just plug into the jack) and the Feather will regulate the 5V USB down to 3.3V.
107 | - **You can also connect a 4.2/3.7V Lithium Polymer** (LiPo/LiPoly) or Lithium Ion (LiIon) battery to the JST jack. This will let the Feather run on a rechargeable battery.
108 | - **When the USB power is powered, it will automatically switch over to USB for power**, as well as start charging the battery (if attached).
109 | - **This happens 'hot-swap' style** so you can always keep the LiPoly connected as a 'backup' power that will only get used when USB power is lost.
110 |
111 |
112 | # **Caveats and Gotchas** #
113 | ## A Note on the Huzzah32 revisions ##
114 | - Check your WROOM version before flashing!
115 | - There is a NEW revision of the huzzah32 shipping with the Wroom-32-**E** that will have some problems initially when plugged into the controller
116 | - This is a result of changes to pin IO12 between the D and E modules (and a bootstrap pin)
117 | - PCB's were made based on result on the Wroom-32-**D** module and have no issues "out of the box"
118 |
119 | - On Wroom-E when the pcb is plugged into the controller at boot similar to boot:0x33 (SPI_FAST_FLASH_BOOT) **invalid header: 0xffffffff**
120 | - You can burn an efuse to work around this with the espefuse tool. Note this is irreversible, if you are uncomfortable with this try to find another vendor with the 32D in stock - How to burn the efuse: `espefuse.py --port [com port] --baud 115200 set_flash_voltage 3.3V` confirm the fuse status with `espefuse -p [com port] --baud 115200 summary`. At the bottom it will say **Flash voltage (VDD_SDIO) set to 3.3V by efuse.**
121 | - At the bottom it will say **Flash voltage (VDD_SDIO) set to 3.3V by efuse.**
122 |
123 | ## Battery Warning ##
124 | - It is *extremely* important that you check the polarity on your battery jack is oriented correctly. There is 0 polarity protection. The charging circuit WILL fry if you plug it in and it's backwards.
125 |
126 | ## Powering Down ##
127 | - Due to the design of the adafruit feather (esp32) there is no formal power switch.
128 | - You must either solder a physical switch on to the battery, **or** unplug it. This is not always easy with the JST connector used so be careful.
129 |
130 | ## Charging ##
131 | - Another unfortunate aspect of the power circuit design on the feather is that the device must be powered on to charge.
132 | - There is no "charging mode" so anytime the controller needs to charge it will be broadcasting.
133 | - Deep sleep is the best solution for this long term but there are reassons it's not included just yet.
134 |
135 | ## Missing Trigger ##
136 | - In windows if you go to look at the button inputs in joy.cpl the right trigger is not displayed.
137 | - The trigger is there, but you have to use another pad tester to "see it".
138 | - The picture below *is the expected behavior* and appears to be a problem with joy.cpl in particular.
139 |
140 |
141 |
142 | ## Various Demos and feature teasers ##
143 | - [Taking Nights for a spin over Bluetooth](https://twitter.com/GamingNJncos/status/1537364206881755136)
144 | - [LCD and customizable Boot Logo](https://twitter.com/GamingNJncos/status/1532819934551724033)
145 | - [Pad Test Demo in X-Men COTA](https://twitter.com/GamingNJncos/status/1537362477817765889)
146 | - [Steamdek Test](https://twitter.com/GamingNJncos/status/1540845741710745602)
147 | - [Early External Unit Testing](https://twitter.com/GamingNJncos/status/1404144038693986307)
148 |
149 | ## Latency Testing ##
150 | - A significant amount of consideration went into making it easy to test code changes and the impact on latency
151 | - The Lightwing PCB has a dedicated solder pad for consistent testing methodology and code incorporates easy to toggle enable/disable for the pin
152 | - Documentation on the process is available [here](https://github.com/GamingNJncos/BLE-3D-Saturn-Public/tree/main/BlueRetro_Latency_Testing)
153 |
154 | ## **Note on the Boot Logos (Supported on HeavyWing PCB)** ##
155 | This is documented in the code however if you want to convert images [this tool](https://lcd-image-converter.riuson.com/en/about/) is really useful
156 |
157 |
158 |
159 | ## Whats with the Names? ##
160 | - Feather add-ons or expansions (hat equivalent for raspberry pi) are called "Wings".
161 | - Combine that with some Sega nerd-lore and you the [Heavy Wing](https://panzerdragoon.fandom.com/wiki/Heavy_Wing) and [Light Wing](https://panzerdragoon.fandom.com/wiki/Light_Wing)
162 |
163 |
164 |
165 | # **Strange notes and pedantic details** #
166 | ## Protocol Details and Resources ##
167 | - [A great overview across numerous sega consoles](https://hackaday.io/project/170365-blueretro/log/180790-evolution-of-segas-io-interface-from-sg-1000-to-saturn) by [darthcloud](https://twitter.com/darthcloud64)
168 | - [Additional protocol details for the Saturn](http://forums.modretro.com/index.php?threads/saturn-controller-protocol-mk80116-mk80100.11328/)
169 |
170 | ## Saturn 3D supported Game list, patent details, and more ##
171 | https://segaretro.org/3D_Control_Pad
172 |
173 | ## Polling Oddity or Opportunity? ##
174 | The [Saturn only polls the 3D protocol at 16ms intervals](https://nfggames.com/forum2/index.php?topic=5055.0) (screen blank). There is however some suggestion in the below post that the Action Replay (this is firmware version specific) can attempt polling faster. It's worth taking a look at as it may be possible to force games into a faster mode with patching.
175 |
176 | Qoute:
177 | "For whatever reason, it's only polling the controller for 14.25ms, with around 310us pauses in between, so it's polling much quicker, but the real issue is after this 14.25ms is up, it then drives the SEL line Hi and goes about it's business for ~2.5ms after that, then back to polling."
178 |
179 | ## Other demos and informational links ##
180 | - [A DIY internal BlueRetro receiver for Saturn](https://twitter.com/nosIndulgences/status/1573719805496299520)
181 | - [Hexfreq showing off a completely differnt bluetooth saturn solution](https://twitter.com/hexfreq/status/1468282054978818062)
182 |
183 | ## **Libraries in use** ##
184 | - [ESP32-BLE-Gamepad](https://github.com/lemmingDev/ESP32-BLE-Gamepad)
185 | - This is subject to change long term as new and improved libraries emerge to support BLE HID gamepads
186 |
187 | - [NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino)
188 |
189 | ## **Details on the Feather** ##
190 | - If you want to remix the PCB's or understand more about the feather itself check out the following
191 | - [Feather Pinouts and hardware overview](https://learn.adafruit.com/adafruit-huzzah32-esp32-feather/pinouts)
192 |
--------------------------------------------------------------------------------
/LightWing/main.cpp:
--------------------------------------------------------------------------------
1 | // Add BLE Gamepad
2 | #include
3 | // Add Sleep
4 | //#include "esp_sleep.h"
5 |
6 | /*
7 | .____ .__ .__ __ __ __.__
8 | | | |__| ____ | |___/ |_/ \ / \__| ____ ____
9 | | | | |/ __ \| | \ __\ \/\/ / |/ \ / __ \
10 | | |___| / /_/ | Y \ | \ /| | | \/ /_/ >
11 | |_______ \ \___ /|___| /__| \__/\ / | |___| /\___ /
12 | \_____\/_____/ \/ \/___\/_____\/______/
13 |
14 | Brought to you by GaminNJncos, Humble Bazooka & Hexfreq
15 | All bugs, poor code choices, and existing PCB designs courtesy of [at]GamingNJncos
16 | */
17 |
18 | /* About this fork
19 | Goal of this fork is to focus on core functionality with the lowest latency
20 | This fork has no support for the Heavywing features including rumble, tilt, or LCD
21 |
22 | As of writing there is no deep sleep support which means you have to unplug the battery on the feather (esp32)
23 | to turn it off, or install a switch on your battery. There is an additional caveat that for charging, the
24 | feather must be turned on. This is a result of the feather and it's charging circuit and not intended as a long
25 | term solution
26 | */
27 |
28 | // BLEGamePad Settings
29 | // ===================
30 | // Values are Advertised Name, Manufacturer, Battery level
31 | // There is a char limit on these
32 | BleGamepad bleGamepad("LightWing", "GnJ & Humble Bazooka", 100);
33 | // Purposely set high to permit ease of future additional button combinationsfor to send Meta, home button, etc
34 | #define numOfButtons 16
35 | #define numOfHatSwitches 1 // DPAD (not Analog pad)
36 | #define enableX true // Analog Pad
37 | #define enableY true // Analog Pad
38 | #define enableAccelerator true // RT
39 | #define enableBrake true // LT
40 | // Additional button options currently disabled
41 | #define enableZ false
42 | #define enableRZ false
43 | #define enableSlider1 false
44 | #define enableSlider2 false
45 | #define enableRudder false
46 | #define enableThrottle false
47 | #define enableRX false
48 | #define enableRY false
49 | #define enableSteering false
50 | // End BLEGamePad Settings
51 |
52 | // Button State Tracking
53 | // This nets a significant advantage in performance vs not tracking states
54 | // BLE expects ACK per packet so flooding "not pressed" or identical data can add extreme delays
55 | //
56 | byte previousButtonStates[numOfButtons];
57 | byte currentButtonStates[numOfButtons];
58 | // Button State Array Map
59 | // The below numeric values are the data returned from poll controller
60 | // Some are binary 0 or 1, while others are a range as read from the 3d controller protocol
61 | //
62 | // --------------------------------------------------------------------
63 | // MODE, DPAD, START, A, B, C, X, Y, Z, L, R, Analog PAD
64 | //
65 | // --------------------------------------------------------------------
66 | // Note Left and Right stick in digital mode will return Binary [0-1] vs [0-15] value in analog mode
67 | // In Digital mode no values are returned from the Analog Stick
68 |
69 | // BLE Gamepad index Mapping
70 | // These are the values for each individual button as they relate to mappings in BLE Gamepad library
71 | // This table might be out of date?
72 |
73 | // PAD BLE Index
74 | // ---------------------
75 |
76 | // Mode 0
77 | // DPAD 1
78 | // START 2
79 | // A 3
80 | // B 4
81 | // C 5
82 | // X 6
83 | // Y 7
84 | // Z 8
85 | // LT 9
86 | // RT 10
87 |
88 |
89 | // Pinmappings for your PCB version
90 | // ================================
91 | // It is manditory you select the correct pinout for your board type
92 | // Failure to do so will cause Segata to light your 3d controller on fire and beat your loved ones
93 |
94 | // Feather LightWing to Controller Pin Mapping
95 | // ===========================================
96 | // PCB: https://oshpark.com/shared_projects/7RqwDWJT
97 | //
98 | int dataPinD0 = 12; // Arthrimus Pin 3 = Data D0
99 | int dataPinD1 = 13; // Arthrimus Pin 2 = Data D1
100 | int dataPinD2 = 14; // Arthrimus Pin 8 = Data D2
101 | int dataPinD3 = 32; // Arthrimus Pin 7 = Data D3
102 | int THPin = 27; // Arthrimus Pin 4 = TH Select
103 | int TRPin = 33; // Arthrimus Pin 5 = TR Request
104 | int TLPin = 15; // Arthrimus Pin 6 = TL Response
105 | int latPin = 4; // Latency testing pin
106 | // End Feather HeavyWing to Controller Pin Mapping
107 | // End all Pin Mappings
108 |
109 | // BleGamepad Variables
110 | // ====================
111 | int16_t bleAnalogX; // Analog pad X Axis Output
112 | int16_t bleAnalogY; // Analog pad Y Axis Output
113 | // DeadZone defined as smallest value to exceed before sending in blegamepad report function
114 | int16_t bleDeadZone = 400; // Set Deadzone via minimum number
115 | // Analog Triggers
116 | int16_t bleRTrigger; // Right Trigger Analog Output
117 | int16_t bleLTrigger; // Left Trigger Analog Output
118 | // End BleGamepad Variables
119 |
120 | // Controller protocol and timing variables
121 | // ========================================
122 | // Data Array for each byte from protocol
123 | boolean dataArrayBit0[8];
124 | boolean dataArrayBit1[8];
125 | boolean dataArrayBit2[8];
126 | boolean dataArrayBit3[8];
127 | boolean dataArrayBit4[8];
128 | boolean dataArrayBit5[8];
129 | boolean dataArrayBit6[8];
130 | boolean dataArrayBit7[8];
131 | // Assorted Protocol Variables
132 | int nibble0Read = 0; // Confirm 1st Nibble has been read
133 | int byteCounter = 0; // Current Byte Tracker
134 | int modeCounter = 4; // Reference for which mode we are currently in Analogue or Digital
135 | int DecodeData = 1; // Controller Successfully Decoded Data Variable
136 | int curMode = 0; // This stores the Controller Mode to pass between ESP cores
137 | // Assorted timing oriented variables
138 | unsigned long timeStamp = 0; // Store time of last update
139 | unsigned long bleTimer = 0;
140 | unsigned long lastTimeStamp = 0; // Store Last time for comparison
141 | const long interval = 1000; // Data update check timing
142 | unsigned long currentMillis = millis(); // check timing
143 | // Directional Variables
144 | int upDownValue = 0;
145 | int leftRightValue = 0;
146 | // Trigger Variables
147 | int ltValue = 0;
148 | int rtValue = 0;
149 | // Variables for Data send request and Acknowledgments
150 | int THSEL = 0;
151 | int TRREQ = 0;
152 | int TLACK = 0;
153 | // Sets the number of Bytes required for Digital or Analogue Modes
154 | int AnalogMode = 6;
155 | int DigitalMode = 3;
156 | // End Controller protocol and timing variables
157 |
158 | // Start CPU variables
159 | // ===================
160 | // These variables are used for CPU Speed settings and tasks
161 | uint32_t Freq = 0; //Used for getCPU debug
162 | //CPU MHz //
163 | int CpuMhz = 40; //Change to set CPU Freq
164 | // End CPU variables
165 |
166 | //int firstBoot = 0; //First Boot check
167 | //-----------------Deep Sleep test---------------
168 | //int firstBoot = 0; //First Boot check //Disabled to test firstboot check in RTC
169 | // This doesn't need to currently be stored in RTC but is helpful to call troubleshooting routines only on power up
170 | RTC_DATA_ATTR int firstBoot = 0; //First Boot check
171 |
172 | // Allocate the interrupt.
173 | ///esp_err_t err = esp_intr_alloc(ETS_INTR_DEFAULT, my_interrupt_handler, NULL, 0);
174 | //if (err != ESP_OK) {
175 | // Handle the error.
176 | //}
177 |
178 | //-----------------Deep Sleep test---------------
179 |
180 | // End CPU variables
181 | // ===================
182 |
183 |
184 | // RTC deep sleep time
185 | //
186 | // This variable defines the length of time to sleep prior to checking for button press
187 | // Intended design is that when in deep sleep a user must hold down a button on the controller
188 | // For longer than the configured deep sleep to wake back up
189 | //
190 | // Current example is 10 seconds
191 | #define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
192 | #define TIME_TO_SLEEP 30 /* Time ESP32 wi go to sleep (in seconds) */
193 |
194 |
195 | // Enter Deep Sleep
196 | void enterDeepSleep()
197 | {
198 | Serial.println("GOING TO DEEP SLEEP ZZZzz...");
199 | // Disable the Bluetooth receiver
200 | //esp_bt_controller_disable();
201 | // Set the Bluetooth controller to power-off mode.
202 | //esp_bt_controller_set_power_mode(ESP_BT_POWER_MODE_OFF, ESP_PD_OPTION_OFF)
203 |
204 | // Set the Bluetooth host stack to power-off mode.
205 | btStop();
206 |
207 | // Delete all of the FreeRTOS tasks
208 | //vTaskDelete(NULL); Needed when core pinning is used with RTOS
209 |
210 |
211 | delay(10);
212 | // Go to deep sleep
213 | esp_deep_sleep_start();
214 | }
215 | // End CPU variables
216 | // ===================
217 |
218 |
219 | // Controller related items
220 | // ========================
221 | void pollController()
222 | {
223 | //bleGamepad.setRightThumb(0,0);
224 | // Check ESP Core Controller Polling Occurs on
225 | // Serial.print("Controller Polling Core ");
226 | // Serial.println(xPortGetCoreID());
227 |
228 | // Start The Data Read
229 | // Is the Controller ready to send the data?
230 | TLACK = digitalRead(TLPin);
231 |
232 | // Have we read all the bytes needed for each mode?
233 | if (byteCounter > modeCounter)
234 | {
235 | // Set Not ready for Data Coms
236 | digitalWrite(THPin, HIGH);
237 | digitalWrite(TRPin, HIGH);
238 |
239 | // Are we using Analogue Mode or Digital?
240 | if (modeCounter == AnalogMode)
241 | {
242 | curMode = 0;
243 | currentButtonStates[0] = 0;
244 | }
245 | else
246 | {
247 | curMode = 1;
248 | currentButtonStates[0] = 1;
249 | }
250 |
251 | // Decoded Controller Data Successfully
252 | // Proceed based on Analog or Digital Mode
253 | //
254 | // Note bleGamepad.isConnected()isconnected check should always happen before gamepadsend
255 |
256 | // This avoids a bug in NIMBLE where blegamepad could under some circumstances attempt button send prior to connecting and cause abort
257 |
258 | if (DecodeData == 1 && bleGamepad.isConnected())
259 |
260 | {
261 | // Analog
262 | if (modeCounter == AnalogMode)
263 | {
264 |
265 | // Analog Mode - Process Input
266 | // Begin all Analog Mode data processing
267 |
268 | // DPAD
269 | if (dataArrayBit6[1] != 0 && dataArrayBit7[1] != 0 && dataArrayBit5[1] != 0 && dataArrayBit4[1] != 0)
270 | {
271 | bleGamepad.setHat1(DPAD_CENTERED);
272 | currentButtonStates[1] = 0;
273 | }
274 | if (dataArrayBit4[1] == 0 && (dataArrayBit7[1] != 0 && dataArrayBit6[1] != 0))
275 | {
276 | // Serial.print(" U");
277 | bleGamepad.setHat1(DPAD_UP);
278 | currentButtonStates[1] = 1;
279 | }
280 | if (dataArrayBit5[1] == 0 && (dataArrayBit7[1] != 0 && dataArrayBit6[1] != 0))
281 | {
282 | // Serial.print(" D");
283 | bleGamepad.setHat1(DPAD_DOWN);
284 | currentButtonStates[1] = 2;
285 | }
286 | if (dataArrayBit6[1] == 0 && (dataArrayBit4[1] != 0 && dataArrayBit5[1] != 0))
287 | {
288 | // Serial.print(" L");
289 | bleGamepad.setHat1(DPAD_LEFT);
290 | currentButtonStates[1] = 3;
291 | }
292 | if (dataArrayBit7[1] == 0 && (dataArrayBit4[1] != 0 && dataArrayBit5[1] != 0))
293 | {
294 | // Serial.print(" R");
295 | bleGamepad.setHat1(DPAD_RIGHT);
296 | currentButtonStates[1] = 4;
297 | }
298 | if (dataArrayBit4[1] == 0 && dataArrayBit6[1] == 0)
299 | {
300 | // Serial.print(" U/L");
301 | bleGamepad.setHat1(DPAD_UP_LEFT);
302 | currentButtonStates[1] = 5;
303 | }
304 | if (dataArrayBit4[1] == 0 && dataArrayBit7[1] == 0)
305 | {
306 | // Serial.print(" U/R");
307 | bleGamepad.setHat1(DPAD_UP_RIGHT);
308 | currentButtonStates[1] = 6;
309 | }
310 | if (dataArrayBit5[1] == 0 && dataArrayBit6[1] == 0)
311 | {
312 | // Serial.print(" D/L");
313 | bleGamepad.setHat1(DPAD_DOWN_LEFT);
314 | currentButtonStates[1] = 7;
315 | }
316 | if (dataArrayBit5[1] == 0 && dataArrayBit7[1] == 0)
317 | {
318 | // Serial.print(" D/R");
319 | bleGamepad.setHat1(DPAD_DOWN_RIGHT);
320 | currentButtonStates[1] = 8;
321 | }
322 | // End DPAD
323 |
324 | // Buttons
325 | if (dataArrayBit3[2] == 0)
326 | {
327 | // Serial.print(" Start ");
328 | bleGamepad.press(BUTTON_12);
329 | currentButtonStates[2] = 1;
330 | }
331 | else
332 | {
333 | bleGamepad.release(BUTTON_12);
334 | currentButtonStates[2] = 0;
335 | }
336 | if (dataArrayBit2[2] == 0)
337 | {
338 | // Serial.print(" A");
339 | bleGamepad.press(BUTTON_4);
340 | currentButtonStates[3] = 1;
341 | }
342 | else
343 | {
344 | // Serial.print(" ");
345 | bleGamepad.release(BUTTON_4);
346 | currentButtonStates[3] = 0;
347 | }
348 | if (dataArrayBit0[2] == 0)
349 | {
350 | // Serial.print(" B");
351 | bleGamepad.press(BUTTON_1);
352 | currentButtonStates[4] = 1;
353 | }
354 | else
355 | {
356 | // Serial.print(" ");
357 | bleGamepad.release(BUTTON_1);
358 | currentButtonStates[4] = 0;
359 | }
360 | if (dataArrayBit1[2] == 0)
361 | {
362 | // Serial.print(" C");
363 | bleGamepad.press(BUTTON_2);
364 | currentButtonStates[5] = 1;
365 | }
366 | else
367 | {
368 | // Serial.print(" ");
369 | bleGamepad.release(BUTTON_2);
370 | currentButtonStates[5] = 0;
371 | }
372 | if (dataArrayBit6[2] == 0)
373 | {
374 | // Serial.print(" X");
375 | bleGamepad.press(BUTTON_7);
376 | currentButtonStates[6] = 1;
377 | }
378 | else
379 | {
380 | // Serial.print(" ");
381 | bleGamepad.release(BUTTON_7);
382 | currentButtonStates[6] = 0;
383 | }
384 | if (dataArrayBit5[2] == 0)
385 | {
386 | // Serial.print(" Y");
387 | bleGamepad.press(BUTTON_5);
388 | currentButtonStates[7] = 1;
389 | }
390 | else
391 | {
392 | // Serial.print(" ");
393 | bleGamepad.release(BUTTON_5);
394 | currentButtonStates[7] = 0;
395 | }
396 | if (dataArrayBit4[2] == 0)
397 | {
398 | // Serial.print(" Z");
399 | bleGamepad.press(BUTTON_8);
400 | currentButtonStates[8] = 1;
401 | }
402 | else
403 | {
404 | // Serial.print(" ");
405 | bleGamepad.release(BUTTON_8);
406 | currentButtonStates[8] = 0;
407 | }
408 | // These can send the trigger presses as a button vs an axis
409 |
410 | /*
411 | if (dataArrayBit3[3] == 0) {
412 | Serial.print(" LTD ");
413 | bleGamepad.press(BUTTON_9);
414 | currentButtonStates[13] = 1; //This cant overlap with LTA state index
415 | } else {
416 | bleGamepad.release(BUTTON_9);
417 | currentButtonStates[13] = 0; //This cant overlap with LTA state index
418 | }
419 |
420 |
421 | // if (dataArrayBit7[2] == 0) {
422 | if (dataArrayBit7[2] == 0) {
423 | Serial.print(" RTD ");
424 | bleGamepad.press(BUTTON_13);
425 | currentButtonStates[14] = 1; //This cant overlap with RTA state index
426 | } else {
427 | bleGamepad.release(BUTTON_13);
428 | currentButtonStates[14] = 0; //This cant overlap with RTA state index
429 | }
430 |
431 | */
432 |
433 |
434 | // Latency Test Pin
435 | // Intended for BlueRetro latency button
436 | // Can be used for other additional buttons
437 | //
438 | // Note this sends "Start" but can be adjusted to press any other button
439 |
440 | /*
441 | if (digitalRead(latPin) == LOW)
442 | {
443 | // Serial.print("LAT");
444 | bleGamepad.press(BUTTON_3);
445 | currentButtonStates[3] = 1;
446 | }
447 | else
448 | {
449 | bleGamepad.release(BUTTON_3);
450 | currentButtonStates[3] = 0;
451 | }
452 |
453 | */
454 | // Up / Down
455 | if (dataArrayBit7[4] == 1)
456 | {
457 | upDownValue = dataArrayBit0[5] + (dataArrayBit1[5] << 1) + (dataArrayBit2[5] << 2) + (dataArrayBit3[5] << 3) + (dataArrayBit4[4] << 4) + (dataArrayBit5[4] << 5) + (dataArrayBit6[4] << 6);
458 |
459 |
460 | bleAnalogX = map(upDownValue, 0, 127, 16384, 32767);
461 |
462 |
463 | }
464 | else
465 | {
466 | upDownValue = !dataArrayBit0[5] + (!dataArrayBit1[5] << 1) + (!dataArrayBit2[5] << 2) + (!dataArrayBit3[5] << 3) + (!dataArrayBit4[4] << 4) + (!dataArrayBit5[4] << 5) + (!dataArrayBit6[4] << 6);
467 |
468 |
469 | bleAnalogX = map(upDownValue, 0, 127, 16383, 1);
470 |
471 |
472 | }
473 | // Deadzone fix - X Axis
474 | // Value is checked based on map output
475 | if ((bleAnalogX < 0 && bleAnalogX > -600)||(bleAnalogX < 0 && bleAnalogX > -600)){
476 | bleAnalogX = 0;
477 | }
478 |
479 | // Analog Debugs
480 | // Serial.print(" bleAnalogX ");
481 | // Serial.println(bleAnalogX);
482 | // Format Value to 3 Chars long
483 | // char buf[] = "000";
484 | // sprintf(buf, "%03i", upDownValue);
485 |
486 | // Left / Right
487 | if (dataArrayBit7[3] == 1)
488 | {
489 | // Serial.print(" R = ");
490 | leftRightValue = dataArrayBit0[4] + (dataArrayBit1[4] << 1) + (dataArrayBit2[4] << 2) + (dataArrayBit3[4] << 3) + (dataArrayBit4[3] << 4) + (dataArrayBit5[3] << 5) + (dataArrayBit6[3] << 6);
491 |
492 |
493 | bleAnalogY = map(leftRightValue, 0, 127, 16384, 32767);
494 |
495 |
496 | }
497 | else
498 | {
499 | leftRightValue = !dataArrayBit0[4] + (!dataArrayBit1[4] << 1) + (!dataArrayBit2[4] << 2) + (!dataArrayBit3[4] << 3) + (!dataArrayBit4[3] << 4) + (!dataArrayBit5[3] << 5) + (!dataArrayBit6[3] << 6);
500 |
501 |
502 | bleAnalogY = map(leftRightValue, 0, 127, 16383, 1);
503 |
504 |
505 | }
506 |
507 | // Deadzone fix - Y Axis
508 | // Value is checked based on map output
509 | if ((bleAnalogY > 0 && bleAnalogY < 600)||(bleAnalogY < 0 && bleAnalogY > -600)){
510 | bleAnalogY = 0;
511 | }
512 | // Set Analog Pad/Left Thumb Stick X Y Values in Blegamepad
513 | // This is an easy place to flip the X and Y results if backwards for your use case
514 | bleGamepad.setX(bleAnalogY);
515 | bleGamepad.setY(bleAnalogX);
516 | // Track State of Analog Sticks X and Y Values
517 | currentButtonStates[11] = bleAnalogX;
518 | currentButtonStates[12] = bleAnalogY;
519 | // unused at this time
520 | // currentButtonStates[13] = 0;
521 | // currentButtonStates[14] = 0;
522 |
523 | // Decode Triggers
524 | char trbuf[] = "00";
525 | // Left Trigger
526 | ltValue = (dataArrayBit7[6] * 8) + (dataArrayBit6[6] * 4) + (dataArrayBit5[6] * 2) + (dataArrayBit4[6] * 1);
527 | bleLTrigger = map(ltValue, 0, 15, 0, 32767);
528 | // Example center fixes if axis issue occur
529 | //if (bleLTrigger == 0){bleLTrigger = 16384;} //center fix
530 | //bleLTrigger = map(ltValue, 0, 15, 0, 255);
531 | //if (bleLTrigger == 0){bleLTrigger = 128;}
532 | // bleGamepad.setLeftTrigger(bleLTrigger);
533 |
534 | bleGamepad.setBrake(bleLTrigger);
535 | // Track State of L trigger
536 | currentButtonStates[9] = bleLTrigger;
537 |
538 | // Debug contents of LTA
539 | //if (bleLTrigger != 128){Serial.print(" LTA = ");Serial.println(bleLTrigger);}
540 |
541 | //sprintf(trbuf, "%02i", ltValue);
542 | // Serial.print(" LT = ");
543 | // Serial.print(trbuf);
544 | // Serial.println(bleLTrigger);
545 |
546 |
547 | // Right Trigger
548 | rtValue = (dataArrayBit7[5] * 8) + (dataArrayBit6[5] * 4) + (dataArrayBit5[5] * 2) + (dataArrayBit4[5] * 1);
549 |
550 | bleRTrigger = map(rtValue, 0, 15, 0, 32767); //Map if 0-32K is range
551 | // Example center fixes if axis issue occur
552 |
553 |
554 | //if (bleRTrigger == 0){bleRTrigger = 16384;} //<--Center Fix for 0-32k Range
555 | //bleRTrigger = map(rtValue, 0, 15, 0, 255); //<-- Map if 0-255 Range
556 | //if (bleRTrigger == 0){bleRTrigger = 128;} // <--Center Fix for 0-255 Range
557 |
558 |
559 | bleGamepad.setAccelerator(bleRTrigger);
560 | // Track State of R trigger
561 | currentButtonStates[10] = bleRTrigger;
562 | // sprintf(trbuf, "%02i", rtValue);
563 |
564 | //Debug contents of LTA
565 | //if (bleRTrigger != 128){Serial.print(" RTA = ");Serial.println(bleRTrigger);}
566 |
567 | // End all Analog Mode data
568 | }
569 | else
570 | {
571 | // Digital Mode - Process Input
572 | // ============================
573 |
574 | // DPAD
575 | if (dataArrayBit6[0] != 0 && dataArrayBit7[0] != 0 && dataArrayBit5[0] != 0 && dataArrayBit4[0] != 0)
576 | {
577 | bleGamepad.setHat1(DPAD_CENTERED);
578 | currentButtonStates[1] = 0;
579 | }
580 | if (dataArrayBit4[0] == 0 && (dataArrayBit7[0] != 0 || dataArrayBit6[0] != 0))
581 | {
582 | // Serial.print(" U ");
583 | bleGamepad.setHat1(DPAD_UP);
584 | currentButtonStates[1] = 1;
585 | }
586 | if (dataArrayBit5[0] == 0 && (dataArrayBit7[0] != 0 || dataArrayBit6[0] != 0))
587 | {
588 | // Serial.print(" D ");
589 | bleGamepad.setHat1(DPAD_DOWN);
590 | currentButtonStates[1] = 2;
591 | }
592 | if (dataArrayBit6[0] == 0 && (dataArrayBit4[0] != 0 || dataArrayBit5[0] != 0))
593 | {
594 | // Serial.print(" L ");
595 | bleGamepad.setHat1(DPAD_LEFT);
596 | currentButtonStates[1] = 3;
597 | }
598 | if (dataArrayBit7[0] == 0 && (dataArrayBit4[0] != 0 || dataArrayBit5[0] != 0))
599 | {
600 | // Serial.print(" R ");
601 | bleGamepad.setHat1(DPAD_RIGHT);
602 | currentButtonStates[1] = 4;
603 | }
604 | if (dataArrayBit4[0] == 0 && dataArrayBit6[0] == 0)
605 | {
606 | // Serial.print(" U/L ");
607 | bleGamepad.setHat1(DPAD_UP_LEFT);
608 | currentButtonStates[1] = 5;
609 | }
610 | if (dataArrayBit4[0] == 0 && dataArrayBit7[0] == 0)
611 | {
612 | // Serial.print(" U/R ");
613 | bleGamepad.setHat1(DPAD_UP_RIGHT);
614 | currentButtonStates[1] = 6;
615 | }
616 | if (dataArrayBit5[0] == 0 && dataArrayBit6[0] == 0)
617 | {
618 | // Serial.print(" D/L ");
619 | bleGamepad.setHat1(DPAD_DOWN_LEFT);
620 | currentButtonStates[1] = 7;
621 | }
622 | if (dataArrayBit5[0] == 0 && dataArrayBit7[0] == 0)
623 | {
624 | // Serial.print(" D/R ");
625 | bleGamepad.setHat1(DPAD_DOWN_RIGHT);
626 | currentButtonStates[1] = 8;
627 | }
628 |
629 | // Buttons
630 |
631 | //------- Start Button -------//
632 |
633 | if (dataArrayBit3[1] == 0)
634 | {
635 | bleGamepad.press(BUTTON_12);
636 | currentButtonStates[2] = 1;
637 | }
638 | else
639 | {
640 | bleGamepad.release(BUTTON_12);
641 | currentButtonStates[2] = 0;
642 | }
643 |
644 | //------- A Button -------//
645 |
646 | if (dataArrayBit2[1] == 0)
647 | {
648 | bleGamepad.press(BUTTON_4);
649 | currentButtonStates[3] = 1;
650 | }
651 | else
652 | {
653 | bleGamepad.release(BUTTON_4);
654 | currentButtonStates[3] = 0;
655 | }
656 |
657 | //------- B Button -------//
658 |
659 | if (dataArrayBit0[1] == 0)
660 | {
661 | bleGamepad.press(BUTTON_1);
662 | currentButtonStates[4] = 1;
663 | }
664 | else
665 | {
666 | bleGamepad.release(BUTTON_1);
667 | currentButtonStates[4] = 0;
668 | }
669 |
670 | //------- C Button -------//
671 |
672 | if (dataArrayBit1[1] == 0)
673 | {
674 | bleGamepad.press(BUTTON_2);
675 | currentButtonStates[5] = 1;
676 | }
677 | else
678 | {
679 | bleGamepad.release(BUTTON_2);
680 | currentButtonStates[5] = 0;
681 | }
682 |
683 | //------- X Button -------//
684 |
685 | if (dataArrayBit6[1] == 0)
686 | {
687 | bleGamepad.press(BUTTON_7);
688 | currentButtonStates[6] = 1;
689 | }
690 | else
691 | {
692 | bleGamepad.release(BUTTON_7);
693 | currentButtonStates[6] = 0;
694 | }
695 |
696 | //------- Y Button -------//
697 |
698 | if (dataArrayBit5[1] == 0)
699 | {
700 | bleGamepad.press(BUTTON_5);
701 | currentButtonStates[7] = 1;
702 | }
703 | else
704 | {
705 | bleGamepad.release(BUTTON_5);
706 | currentButtonStates[7] = 0;
707 | }
708 |
709 | //------- Z Button -------//
710 |
711 | if (dataArrayBit4[1] == 0)
712 | {
713 | bleGamepad.press(BUTTON_8);
714 | currentButtonStates[8] = 1;
715 | }
716 | else
717 | {
718 | bleGamepad.release(BUTTON_8);
719 | currentButtonStates[8] = 0;
720 | }
721 |
722 | //------- LT Button -------//
723 |
724 | if (dataArrayBit3[2] == 0)
725 | {
726 | //bleGamepad.press(BUTTON_9);
727 | //bleGamepad.setBrake(32767);
728 | bleGamepad.setBrake(255);
729 | currentButtonStates[9] = 1;
730 | }
731 | else
732 | {
733 | //bleGamepad.release(BUTTON_9);
734 | bleGamepad.setBrake(0);
735 | currentButtonStates[9] = 0;
736 | }
737 |
738 | //------- RT Button -------//
739 |
740 | if (dataArrayBit7[1] == 0)
741 | {
742 | //bleGamepad.setAccelerator(32767);
743 | bleGamepad.setAccelerator(255);
744 | currentButtonStates[10] = 1;
745 | }
746 | else
747 | {
748 | //bleGamepad.release(BUTTON_10);
749 | bleGamepad.setAccelerator(0);
750 | currentButtonStates[10] = 0;
751 | }
752 |
753 | /*
754 | // Latency Test Pin
755 | // Intended for BlueRetro latency test pad to measure BLEGamepad update speeds without modifying the Controller
756 | //
757 | // Use print enabled to test your setup, then disable the prints as they will impact latency negatively
758 | if (digitalRead(latPin) == LOW)
759 | {
760 | Serial.print("Latency Test Press");
761 | bleGamepad.press(BUTTON_3);
762 | currentButtonStates[2] = 1;
763 | }
764 | else
765 | {
766 | bleGamepad.release(BUTTON_3);
767 | currentButtonStates[2] = 0;
768 | }
769 | */
770 | }
771 | // End Digital Mode - Process Input
772 | // ================================
773 |
774 | // RTOS Watermark check
775 | // unsigned int wMark2 = uxTaskGetStackHighWaterMark(nullptr);
776 | // printf("Watermark - SendReport B loop %u\n", wMark2);
777 |
778 | // All Input states gathered Send Update if state has changed
779 | // This is how blegampad library runs the check but you can't compare arrays like this so condition is always true
780 | // Substantially higher power consumption as a result of constant transmit
781 | if (currentButtonStates != previousButtonStates)
782 | {
783 | for (byte currentIndex = 0; currentIndex < numOfButtons; currentIndex++)
784 | // To do this the correct way - itterate over each index but it has problems with loss of single packet
785 | //if (currentButtonStates[currentIndex] != previousButtonStates[currentIndex]) {
786 | // for (byte currentIndex = 0; currentIndex < numOfButtons; currentIndex++){
787 | {
788 | previousButtonStates[currentIndex] = currentButtonStates[currentIndex];
789 | }
790 | bleGamepad.sendReport();
791 | bleTimer = timeStamp;
792 | //bleTimer = millis();
793 | }
794 | }
795 |
796 |
797 | // Invalid Data or no connection error state
798 | // =========================================
799 | // Communication or wiring issue
800 |
801 | else
802 | {
803 | for (int printByteCounter = 0; printByteCounter < modeCounter + 1; printByteCounter++)
804 | {
805 | int derpvar;
806 | derpvar = 0;
807 | // Serial.println("Error: Gamepad may not be paired OR Pinout/Timing Incorrect");
808 | // Uncomment lines for additional debug output
809 | // Serial.print(" -- Byte ");
810 | // Serial.print(printByteCounter);
811 | // Serial.print(" - ");
812 | // Serial.print(dataArrayBit0[printByteCounter]);
813 | // Serial.print(dataArrayBit1[printByteCounter]);
814 | // Serial.print(dataArrayBit2[printByteCounter]);
815 | // Serial.print(dataArrayBit3[printByteCounter]);
816 | // Serial.print(dataArrayBit4[printByteCounter]);
817 | // Serial.print(dataArrayBit5[printByteCounter]);
818 | // Serial.print(dataArrayBit6[printByteCounter]);
819 | // Serial.print(dataArrayBit7[printByteCounter]);
820 | }
821 | // End Invalid Data
822 | //=================
823 | }
824 | // End Polling
825 | // ===========
826 |
827 | // Reset variables ready for data read.
828 | byteCounter = 0;
829 | nibble0Read = 0;
830 |
831 | // Setting Current Time for data read
832 | timeStamp = millis();
833 | }
834 |
835 | // Check to see if the Controller is ready to send data and if we have read any data yet
836 | if (TLACK == HIGH and nibble0Read == 0)
837 | {
838 | digitalWrite(THPin, LOW);
839 | delayMicroseconds(4); // I don't think I need this
840 | digitalWrite(TRPin, LOW);
841 | delayMicroseconds(4);
842 | // delayMicroseconds(1);
843 | }
844 |
845 | // If the 1st nibble is being sent and we havn't read the 1st nibble yet get the data from the pins
846 | if (TLACK == LOW and nibble0Read == 0)
847 | {
848 | // Sets ready to read the 1st nibble of data
849 | digitalWrite(TRPin, HIGH);
850 | delayMicroseconds(8); // For ESP32 with lower setting get random button press
851 |
852 | // Read the Data for the 1st Nibble
853 | dataArrayBit0[byteCounter] = digitalRead(dataPinD0);
854 | dataArrayBit1[byteCounter] = digitalRead(dataPinD1);
855 | dataArrayBit2[byteCounter] = digitalRead(dataPinD2);
856 | dataArrayBit3[byteCounter] = digitalRead(dataPinD3);
857 |
858 | if (dataArrayBit0[byteCounter] > 1)
859 | {
860 | dataArrayBit0[byteCounter] = 0;
861 | }
862 | if (dataArrayBit1[byteCounter] > 1)
863 | {
864 | dataArrayBit1[byteCounter] = 0;
865 | }
866 | if (dataArrayBit2[byteCounter] > 1)
867 | {
868 | dataArrayBit2[byteCounter] = 0;
869 | }
870 | if (dataArrayBit3[byteCounter] > 1)
871 | {
872 | dataArrayBit3[byteCounter] = 0;
873 | }
874 |
875 | // 1st Nibble has been read
876 | nibble0Read = 1;
877 |
878 | // Check if we are reading data for Analogue mode or Digital Mode
879 | // The mode defines the number of Bytes we need to read
880 | if (byteCounter == 0)
881 | {
882 | if ((dataArrayBit0[0] == 1 and dataArrayBit1[0] == 0 and dataArrayBit2[0] == 0 and dataArrayBit3[0] == 0) or (dataArrayBit0[0] == 0 and dataArrayBit1[0] == 1 and dataArrayBit2[0] == 1 and dataArrayBit3[0] == 0) or (dataArrayBit0[0] == 1 and dataArrayBit1[0] == 1 and dataArrayBit2[0] == 1 and dataArrayBit3[0] == 0))
883 | {
884 | modeCounter = AnalogMode;
885 | }
886 | else
887 | {
888 | modeCounter = DigitalMode;
889 | }
890 | }
891 | }
892 |
893 | // Check if the 2nd Nibble is being sent and if we have already read the 1st Nibble
894 | if (TLACK == HIGH and nibble0Read == 1)
895 | {
896 | // Sets ready to read the 2nd Nibble
897 | digitalWrite(TRPin, LOW);
898 | delayMicroseconds(8);
899 | // Read the data for the 2nd Nibble
900 | dataArrayBit4[byteCounter] = digitalRead(dataPinD0);
901 | dataArrayBit5[byteCounter] = digitalRead(dataPinD1);
902 | dataArrayBit6[byteCounter] = digitalRead(dataPinD2);
903 | dataArrayBit7[byteCounter] = digitalRead(dataPinD3);
904 | if (dataArrayBit4[byteCounter] > 1)
905 | {
906 | dataArrayBit4[byteCounter] = 0;
907 | }
908 | if (dataArrayBit5[byteCounter] > 1)
909 | {
910 | dataArrayBit5[byteCounter] = 0;
911 | }
912 | if (dataArrayBit6[byteCounter] > 1)
913 | {
914 | dataArrayBit6[byteCounter] = 0;
915 | }
916 | if (dataArrayBit7[byteCounter] > 1)
917 | {
918 | dataArrayBit7[byteCounter] = 0;
919 | }
920 |
921 | // Reset the 1st Nibble read variable, ready for the next Byte of data
922 | nibble0Read = 0;
923 |
924 | // Increase the Byte counter by 1 so we are ready to read the next Byte of data
925 | byteCounter++;
926 | }
927 |
928 | // Time Stamp Routines to check if data has paused.
929 | currentMillis = millis();
930 |
931 | if (currentMillis - timeStamp >= interval)
932 | {
933 | // Resetting All Variables
934 | timeStamp = millis();
935 | digitalWrite(THPin, HIGH);
936 | digitalWrite(TRPin, HIGH);
937 | byteCounter = 0;
938 | nibble0Read = 0;
939 | Serial.println("Init Controller Protocol...");
940 | }
941 | }
942 | //=============================
943 | // End Controller related items
944 |
945 |
946 |
947 | // CPU Speed related items
948 | //=============================
949 | //Set CPU Speed
950 | //
951 | // This will heavily impact GPIO speed and protocol level checkins with the controller
952 | // Seriously.
953 | // For more information see the following link where this code was shamelessly borrowed from
954 | // https://deepbluembedded.com/esp32-change-cpu-speed-clock-frequency/
955 | //
956 | void setCpu()
957 | {
958 | //This sets the CPU frequency
959 | //Possible frequencies are directly tied to your own device so dont just yolo values in here and then cry
960 | //
961 | //function takes the following frequencies as valid values:
962 | // 240, 160, 80 <<< For all XTAL types
963 | // 40, 20, 10 <<< For 40MHz XTAL
964 | // 26, 13 <<< For 26MHz XTAL
965 | // 24, 12 <<< For 24MHz XTAL
966 | //Print initial Speed
967 | Freq = getCpuFrequencyMhz();
968 | Serial.print("Current CPU Freq = ");
969 | Serial.print(Freq);
970 | Serial.println(" MHz");
971 | delay(30);
972 | Serial.end(); //Required for ESP bug
973 | setCpuFrequencyMhz(40);
974 | delay(30);
975 | Serial.begin(115200); // Required for ESP bug
976 | delay(30);
977 | Freq = getCpuFrequencyMhz();
978 | Serial.print("New CPU Freq = ");
979 | Serial.print(Freq);
980 | Serial.println(" MHz");
981 | }
982 |
983 | //Read CPU Speed and Clock
984 | void getCPU()
985 | {
986 | Freq = getCpuFrequencyMhz();
987 | Serial.print("Boot CPU Freq = ");
988 | Serial.print(Freq);
989 | Serial.println(" MHz");
990 | Freq = getXtalFrequencyMhz();
991 | Serial.print("My XTAL Freq = ");
992 | Serial.print(Freq);
993 | Serial.println(" MHz");
994 | Freq = getApbFrequency();
995 | Serial.print("My APB Freq = ");
996 | Serial.print(Freq);
997 | Serial.println(" Hz");
998 | }
999 | //=============================
1000 | // End CPU Speed related items
1001 |
1002 |
1003 | // This is the main loop due to threading in arduino + core tasking in RTOS
1004 | //==========================================================================
1005 | void setup()
1006 | {
1007 |
1008 |
1009 | // Start BLE Gamepad
1010 | BleGamepadConfiguration bleGamepadConfig;
1011 | bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD); // CONTROLLER_TYPE_JOYSTICK, CONTROLLER_TYPE_GAMEPAD (DEFAULT), CONTROLLER_TYPE_MULTI_AXIS
1012 | //bleGamepadConfig.setControllerType(CONTROLLER_TYPE_MULTI_AXIS); //Axis will break Windows Gamepad test function but may work in games
1013 | bleGamepadConfig.setButtonCount(numOfButtons);
1014 | bleGamepadConfig.setWhichAxes(enableX, enableY, enableZ, enableRX, enableRY, enableRZ, enableSlider1, enableSlider2); // Can also be done per-axis individually. All are true by default
1015 | bleGamepadConfig.setHatSwitchCount(numOfHatSwitches); // 1 by default
1016 |
1017 | //Trigger settings
1018 | //Emulate Xbox behavior to avoid rY and rZ use
1019 | bleGamepadConfig.setIncludeAccelerator(true);
1020 | bleGamepadConfig.setIncludeBrake(true);
1021 |
1022 | //Modify HID Range Values
1023 | // WARNING: This impacts all MAP statements and Im lazy so it's not just defined as global variable
1024 |
1025 | //
1026 | //Set Range default -32k to +32k
1027 | //bleGamepadConfig.setAxesMin(0x8001); // -32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
1028 | //bleGamepadConfig.setAxesMax(0x7FFF); // 32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
1029 | //
1030 | //== Set Range Axes Range
1031 | // Emulate Xbox 0-255
1032 | bleGamepadConfig.setAxesMin(0x00); //Set Min to 0 //try 0 as min similar to xbox
1033 | //bleGamepadConfig.setAxesMax(0xFF); //Set Max to 255 // try 255 as Max similar to xbox //removed leading 00s
1034 | ///== Set Trigger Range
1035 | // Emulate Xbox 0-255
1036 | bleGamepadConfig.setSimulationMin(0x00);
1037 | //bleGamepadConfig.setSimulationMax(0xFF); //Max 255 //This doesn't seem to work right for BLEgamepad
1038 |
1039 | bleGamepadConfig.setAxesMin(0x0001); // -32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
1040 | //
1041 | // if blegamepad for Accel and Bake don't report try this instead
1042 | //bleGamepadConfig.setWhichSimulationControls(enableRudder, enableThrottle, enableAccelerator, enableBrake, enableSteering);
1043 |
1044 | //==Adjust Vid and PID
1045 | // These can be set to advertise various vendor and product IDs from other controllers
1046 | // bleGamepadConfig.setVid(0x45e);
1047 | // bleGamepadConfig.setPid(0x2e0);
1048 |
1049 | // ==Other Available Special Button Options
1050 | // Intermittent results with these "special buttons" across all tested remote devices
1051 | //
1052 | // bleGamepadConfig.setIncludeStart(true);
1053 | // bleGamepadConfig.setIncludeSelect(true);
1054 | // bleGamepadConfig.setIncludeMenu(true);
1055 | // bleGamepadConfig.setIncludeHome(true);
1056 | // bleGamepadConfig.setIncludeBack(true);
1057 | // bleGamepadConfig.setIncludeVolumeInc(true);
1058 | // bleGamepadConfig.setIncludeVolumeDec(true);
1059 | // bleGamepadConfig.setIncludeVolumeMute(true);
1060 | //
1061 | // ==Use or disable BLEGampead AutoReporting
1062 | // AutoReport can impact latency negatively with high speed of updates
1063 | bleGamepadConfig.setAutoReport(false); // This is true by default
1064 |
1065 | //Use all the bleGamepad Settings to initiate controller
1066 | bleGamepad.begin(&bleGamepadConfig);
1067 |
1068 | // Setting input and output pins for Comms with Controller
1069 | // Use Heavy and Lightwing pinout settings instead of changing this
1070 | //==========================// Pin 1 = +5V
1071 | pinMode(dataPinD1, INPUT); // Pin 2 = Data D1
1072 | pinMode(dataPinD0, INPUT); // Pin 3 = Data D0
1073 | pinMode(THPin, OUTPUT); // Pin 4 = TH Select
1074 | pinMode(TRPin, OUTPUT); // Pin 5 = TR Request
1075 | pinMode(TLPin, INPUT); // Pin 6 = TL Response
1076 | pinMode(dataPinD3, INPUT); // Pin 7 = Data D3
1077 | pinMode(dataPinD2, INPUT); // Pin 8 = Data D2
1078 | //==========================// Pin 9 = GND
1079 |
1080 | // Set pin state to begin reading controller state
1081 | digitalWrite(THPin, HIGH);
1082 | digitalWrite(TRPin, HIGH);
1083 |
1084 | // Define Latency test pin
1085 | pinMode(latPin, INPUT_PULLUP);
1086 |
1087 | // Setup Serial comms for Serial Monitor
1088 | Serial.begin(115200);
1089 | Serial.println("Device Booting....");
1090 | }
1091 |
1092 | // Loop will always run on Core 1
1093 | void loop()
1094 | {
1095 | //Settings related to initial boot of device
1096 | //This doesn't get called on wake from deep sleep
1097 | if (firstBoot == 0){
1098 | getCPU();
1099 | //setCpu();
1100 | firstBoot=1;
1101 | }
1102 |
1103 | pollController();
1104 | }
1105 |
--------------------------------------------------------------------------------
/HeavyWing/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | // Add BLE Gamepad
4 | #include
5 | // Add OLED
6 | #include
7 | #include
8 | // Add Adafruit Sensor Libs for Tilt Controls
9 | #include
10 | #include
11 |
12 | //====================================================
13 | // __________.____ ___________.________ _________
14 | // \______ \ | \_ _____/ \_____ \\______ \
15 | // | | _/ | | __)_ _(__ < | | \
16 | // | | \ |___ | \ / \| ` \
17 | // |______ /_______ \/_______ / /______ /________ /
18 | // \/ \/ \/ \/ \/
19 | // Greetz and massive thanks to Hexfreq for being a complete bad ass
20 | //
21 | // All reliable controller code foundation is from [at]Hexfreq
22 | // All bugs, poor code choices, and existing PCB designs courtesy of [at]GamingNJncos
23 | // Cheers to [at]Arthrimus for lighting this fire on accident
24 | //
25 | // As I have limited time for mainting this codebase long term attempts have been made to over document code provided
26 | // No Warranty expressed or implied
27 | //====================================================
28 |
29 |
30 | // OLED Screen Settings
31 | #define SCREEN_WIDTH 128 // OLED display width, in pixels
32 | #define SCREEN_HEIGHT 64 // OLED display height, in pixels
33 | #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
34 | #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
35 | Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
36 |
37 | // Establish tasks for ESP32 CPU Core Pinning
38 | TaskHandle_t Task1;
39 | TaskHandle_t Task2;
40 |
41 | // BLEGamePad Settings
42 | // ===================
43 | // Values are Advertised Name, Manufacturer, Battery level
44 | // Note the battery value is not from a read value here but later blegamepad examples support live update vs 1 time poll
45 | BleGamepad bleGamepad("Reala", "GamingNJncos.HexFreq", 100);
46 | // Purposely set high to permit ease of future additional button combinationsfor to send Meta, home button, etc
47 | #define numOfButtons 12
48 | #define numOfHatSwitches 1 //DPAD (not Analog pad)
49 | #define enableX true // Analog Pad
50 | #define enableY true // Analog Pad
51 | #define enableRX true // Triggers
52 | #define enableRY true // Triggers
53 | // Additional button options currently disabled
54 | #define enableZ false
55 | #define enableRZ false
56 | #define enableSlider1 false
57 | #define enableSlider2 false
58 | #define enableRudder false
59 | #define enableThrottle false
60 | #define enableAccelerator false
61 | #define enableBrake false
62 | #define enableSteering false
63 | // End BLEGamePad Settings
64 |
65 | // Button State Tracking
66 | // This nets a significant advantage in performance vs not tracking states
67 | // BLE expects ACK per packet so flooding "not pressed" or identical data can add extreme delays
68 | //
69 | byte previousButtonStates[12];
70 | byte currentButtonStates[12];
71 | // Button State Array Map
72 | // ======================
73 | // MODE, DPAD, START, A, B, C, X, Y, Z, L, R, Analog PAD
74 | // [0-1] [0-8] [- Binary Values 0-1 -] [0-15] [0-127,0-127]
75 | // Note Left and Right stick in digital mode will return Binary [0-1] vs [0-15] value in analog mode
76 |
77 | // Pinmappings for your PCB version
78 | // It is manditory you select the correct pinout for your board type
79 |
80 | // Feather HeavyWing to Controller Pin Mapping
81 | // ===========================================
82 | //PCB: https://oshpark.com/shared_projects/ki7HbZV4
83 | //
84 | //int dataPinD0 = 32; // Arthrimus Pin 3 = Data D0
85 | //int dataPinD1 = 14; // Arthrimus Pin 2 = Data D1
86 | //int dataPinD2 = 13; // Arthrimus Pin 8 = Data D2
87 | //int dataPinD3 = 12; // Arthrimus Pin 7 = Data D3
88 | //int THPin = 15; // Arthrimus Pin 4 = TH Select
89 | //int TRPin = 33; // Arthrimus Pin 5 = TR Request
90 | //int TLPin = 27; // Arthrimus Pin 6 = TL Response
91 | //int batPin = A13; // Used by BLEGamepad library
92 | //int latPin = 4; // Latency testing pin
93 | // End Feather HeavyWing to Controller Pin Mapping
94 |
95 |
96 | // Feather LightWing to Controller Pin Mapping
97 | // ===========================================
98 | // PCB: https://oshpark.com/shared_projects/7RqwDWJT
99 | //
100 | int dataPinD0 = 12; // Arthrimus Pin 3 = Data D0
101 | int dataPinD1 = 13; // Arthrimus Pin 2 = Data D1
102 | int dataPinD2 = 14; // Arthrimus Pin 8 = Data D2
103 | int dataPinD3 = 32; // Arthrimus Pin 7 = Data D3
104 | int THPin = 27; // Arthrimus Pin 4 = TH Select
105 | int TRPin = 33; // Arthrimus Pin 5 = TR Request
106 | int TLPin = 15; // Arthrimus Pin 6 = TL Response
107 | int batPin = A13; // Used by BLEGamepad library
108 | int latPin = 4; // Latency testing pin
109 | // End Feather HeavyWing to Controller Pin Mapping
110 | // End all Pin Mappings
111 |
112 | // BleGamepad Variables
113 | // ====================
114 | int16_t bleAnalogX; //Analog pad X Axis Output
115 | int16_t bleAnalogY; //Analog pad Y Axis Output
116 | // DeadZone defined as smallest value to exceed before sending in blegamepad report function
117 | int16_t bleDeadZone = 400; //Set Deadzone via minimum number
118 | // Analog Triggers
119 | int16_t bleRTrigger; //Right Trigger Analog Output
120 | int16_t bleLTrigger; //Left Trigger Analog Output
121 | // Battery Monitoring variables for BLEGamepad
122 | // Note BLE Gamepad can read battery percent but can not check to transmit value after initial connection
123 | int adcRead = 0;
124 | int batVolt = 0;
125 | // End BleGamepad Variables
126 |
127 |
128 | // Controller protocol and timing variables
129 | // ========================================
130 | // Data Array for each byte from protocol
131 | boolean dataArrayBit0[8];
132 | boolean dataArrayBit1[8];
133 | boolean dataArrayBit2[8];
134 | boolean dataArrayBit3[8];
135 | boolean dataArrayBit4[8];
136 | boolean dataArrayBit5[8];
137 | boolean dataArrayBit6[8];
138 | boolean dataArrayBit7[8];
139 | // Assorted Protocol Variables
140 | int nibble0Read = 0; // Confirm 1st Nibble has been read
141 | int byteCounter = 0; // Current Byte Tracker
142 | int modeCounter = 4; // Reference for which mode we are currently in Analogue or Digital
143 | int DecodeData = 1; // Controller Successfully Decoded Data Variable
144 | int curMode = 0; // This stores the Controller Mode to pass between ESP cores
145 | // Assorted timing oriented variables
146 | unsigned long timeStamp = 0; // Store time of last update
147 | unsigned long lastTimeStamp = 0; // Store Last time for comparison
148 | const long interval = 1000; // Data update check timing
149 | unsigned long currentMillis = millis(); // check timing
150 | // Directional Variables
151 | int upDownValue = 0;
152 | int leftRightValue = 0;
153 | // Trigger Variables
154 | int ltValue = 0;
155 | int rtValue = 0;
156 | // Variables for Data send request and Acknowledgments
157 | int THSEL = 0;
158 | int TRREQ = 0;
159 | int TLACK = 0;
160 | // Sets the number of Bytes required for Digital or Analogue Modes
161 | int AnalogMode = 6;
162 | int DigitalMode = 3;
163 | // End Controller protocol and timing variables
164 |
165 |
166 | // Gyro and Accelerometer Variables
167 | // =================================
168 | // Gyro is currently disabled in code but my terrible examples should be useful if you wish to use this feature
169 | const int MPU_addr=0x68; // Define Gyro I2C Address
170 | int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; // Store all values from MPU
171 | int minVal=265;
172 | int maxVal=402;
173 | double x;
174 | double y;
175 | double z;
176 | // Converted XY Values to BLEGamepad ranges (negative to positive 32K
177 | int xmap;
178 | int ymap;
179 | // Max Values to limit full range of 360 degree motion.
180 | // Will require calibration with your MPU-6050 to identify most comfortable ranges
181 | // Suggest 35-45 Degrees or less relatively comfortable for most use cases
182 | int xmax = 200;
183 | int ymax = 200;
184 | int xmin = 160;
185 | int ymin = 160;
186 | // End Gyro and Accelerometer Variables
187 |
188 |
189 | // Boot Logo
190 | // ==========
191 | //Set Image Size for Boot Logo
192 | #define imageWidth 128
193 | #define imageHeight 64
194 | // Image to be displayed
195 | // These can be changed and alternatively set as animations
196 | // Create with "LCD Image Converter" tool or similar
197 | // https://lcd-image-converter.riuson.com/en/about/
198 | const unsigned char myBitmap [] PROGMEM=
199 | {
200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 | 0x0F, 0xFE, 0x0C, 0x00, 0xF6, 0x0C, 0x3C, 0x00, 0x60, 0x41, 0x80, 0x87, 0xFF, 0xF1, 0x80, 0x1E,
210 | 0x1E, 0x3F, 0xFB, 0xE7, 0x9E, 0x0E, 0x3E, 0x00, 0xE7, 0xBE, 0x7F, 0x03, 0xBF, 0x1E, 0xE0, 0x0E,
211 | 0x3C, 0x03, 0xE0, 0x7E, 0x03, 0x1E, 0x3E, 0x00, 0xE4, 0x1E, 0x0F, 0x03, 0x1E, 0x1E, 0x78, 0x0C,
212 | 0x3E, 0x01, 0xE0, 0x1E, 0x01, 0x1E, 0x3E, 0x01, 0xF0, 0x1E, 0x0F, 0x03, 0x1E, 0x0F, 0x3C, 0x0C,
213 | 0x3F, 0x01, 0xE1, 0x3E, 0x00, 0x3F, 0x1F, 0x03, 0xF0, 0x1E, 0x0F, 0x03, 0x1E, 0x0F, 0x3F, 0x0C,
214 | 0x1F, 0xC1, 0xE3, 0x3C, 0x00, 0x3D, 0x1F, 0x03, 0xD8, 0x1E, 0x0F, 0x03, 0x1E, 0x1E, 0x3F, 0x8C,
215 | 0x0F, 0xF1, 0xFF, 0x3C, 0x00, 0x79, 0x9F, 0x87, 0xD8, 0x1E, 0x0F, 0x03, 0x1E, 0x3E, 0x3F, 0xCC,
216 | 0x03, 0xF9, 0xFF, 0x3C, 0x00, 0xF9, 0x8F, 0x87, 0x8C, 0x1E, 0x0F, 0x03, 0x1E, 0xF0, 0x27, 0xEC,
217 | 0x00, 0xFD, 0xE3, 0x3C, 0x1F, 0xF0, 0xCF, 0xCF, 0x8C, 0x1E, 0x0F, 0x03, 0x1E, 0x78, 0x31, 0xFC,
218 | 0x40, 0x7D, 0xE0, 0x3E, 0x0F, 0xF0, 0xC7, 0xCF, 0x06, 0x1E, 0x0F, 0x03, 0x1E, 0x78, 0x30, 0xFC,
219 | 0x60, 0x3D, 0xE0, 0x3E, 0x07, 0xE0, 0x67, 0xDF, 0x06, 0x1E, 0x0F, 0x03, 0x1E, 0x3C, 0x30, 0x7C,
220 | 0x30, 0x3D, 0xE0, 0x7E, 0x07, 0xE0, 0x63, 0xFE, 0x03, 0x1E, 0x07, 0x87, 0x1E, 0x3E, 0x30, 0x3C,
221 | 0x3E, 0xF9, 0xF3, 0xFF, 0x0F, 0xE0, 0x73, 0xFE, 0x07, 0xBE, 0x07, 0xFE, 0x1F, 0x1F, 0x30, 0x0C,
222 | 0x1F, 0xE3, 0xFF, 0xE3, 0xFF, 0xE0, 0xFB, 0xFE, 0x07, 0xFF, 0x01, 0xF8, 0x3F, 0x87, 0xF0, 0x04,
223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
232 | };
233 | // End Boot Logo
234 |
235 |
236 | // Boot Logo and Screen Setup
237 | // ==========================
238 | void bootLogo(){
239 | //Check ESP Core Boot Logo is running on
240 | //Serial.print("BootLogo Core ");
241 | //Serial.println(xPortGetCoreID());
242 |
243 | if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
244 | Serial.println(F("SSD1306 allocation failed"));
245 | for(;;); // Don't proceed, loop forever
246 | }
247 | // Rotate
248 | display.setRotation(2);
249 | // Clear the Buffer
250 | display.clearDisplay();
251 | // Draw Animation
252 | // Draw Bitmap syntax
253 | // display.drawBitmap(x position, y position, bitmap data, bitmap width, bitmap height, color)
254 | display.drawBitmap(0, 32, myBitmap, 128, 32, WHITE);
255 | display.display();
256 | // Set Delay for Boot Animation
257 | delay(1500);
258 | // Reset Display
259 | display.display();
260 | display.setRotation(2);
261 | delay(10);
262 | // Clear the buffer
263 | display.clearDisplay();
264 | delay(2000);
265 | //End Screen Setup
266 | }
267 |
268 |
269 | // Battery Related Checks
270 | // ======================
271 | void getBatStat(){
272 | // Check ESP Core
273 | //Serial.print("Battery Status Core ");
274 | //Serial.println(xPortGetCoreID());
275 |
276 | adcRead = analogRead(batPin);
277 | batVolt = adcRead;
278 | // Multiply by 2 to correct reading for Featherwing Huzzah32
279 | //batVolt = adcRead * 2;
280 |
281 | int BatteryPct;
282 | int oldBatPct = 0;
283 | // Map Battery voltage range to a percentage
284 | BatteryPct = map (batVolt, 1200, 4200, 0, 100);
285 | // Make sure its populated on initial run
286 | if (oldBatPct < 1){
287 | oldBatPct = BatteryPct;
288 | }
289 | // Super hack check to omit negative values from OLED Updates
290 | if (BatteryPct < 0 ){
291 | BatteryPct = oldBatPct;
292 | }
293 |
294 | // Build and send screen update
295 | // ============================
296 | String lcdBat;
297 | lcdBat = "Battery: " + String(BatteryPct) + "% ";
298 | //display.setCursor(0,50);
299 | //display.print("Battery ");
300 | //display.setCursor(0,50);
301 | //display.print(lcdBat);
302 | //display.display();
303 | // End Battery Updates
304 | }
305 |
306 | // OLED Updates
307 | // ============
308 | void oled_Updates(){
309 | if (curMode== 0 ) {
310 | curMode = 0;
311 | display.setTextSize(1); // Normal 1:1 pixel scale
312 | display.setTextColor(SSD1306_WHITE, BLACK); // Draw white text
313 | display.setCursor(0,1); // Start at top-left corner
314 | display.println(F("Mode: Analog "));
315 | display.display();
316 | } else {
317 | curMode = 1;
318 | display.setTextSize(1); // Normal 1:1 pixel scale
319 | display.setTextColor(SSD1306_WHITE, BLACK); // Draw white text
320 | display.setCursor(0,1); // Start at top-left corner
321 | display.println(F("Mode: Digital "));
322 | display.display();
323 | }
324 | // End OLED Updates
325 | }
326 |
327 |
328 | // Controller related items
329 | // ========================
330 | void pollController(){
331 | //Check ESP Core Controller Polling Occurs on
332 | //Serial.print("Controller Polling Core ");
333 | //Serial.println(xPortGetCoreID());
334 |
335 | //Make sure that we sync timestamp and last timestamp on first run
336 | if (lastTimeStamp = 0){
337 | lastTimeStamp = timeStamp;
338 | //hacktest MPU initialization on first run
339 | //initializeSensor();
340 | }
341 |
342 | // Start The Data Read
343 | // Is the Controller ready to send the data?
344 | TLACK = digitalRead(TLPin);
345 |
346 | // Have we read all the bytes needed for each mode?
347 | if (byteCounter > modeCounter) {
348 | // Set Not ready for Data Coms
349 | digitalWrite(THPin, HIGH);
350 | digitalWrite(TRPin, HIGH);
351 |
352 | // Are we using Analogue Mode or Digital?
353 | if (modeCounter == AnalogMode) {
354 | curMode = 0;
355 | currentButtonStates[0] = 0;
356 | } else {
357 | curMode = 1;
358 | currentButtonStates[0] = 1;
359 | }
360 |
361 | // Decoded Controller Data Successfully
362 | // Proceed based on Analog or Digital Mode
363 | //
364 | // Note that BLEgamepad check occurs in combination with successfully decoded data
365 | // This avoids a bug in NIMBLE where blegamepad could under some circumstances attempt button send prior to connecting and cause abort
366 | if (DecodeData == 1 && bleGamepad.isConnected()) {
367 | //Analog
368 | if (modeCounter == AnalogMode) {
369 | //Analog Mode - Process Input
370 | //Begin all Analog Mode data processing
371 |
372 | //DPAD
373 | if (dataArrayBit6[1] != 0 && dataArrayBit7[1] != 0 && dataArrayBit5[1] != 0 && dataArrayBit4[1] != 0){
374 | bleGamepad.setHat1(DPAD_CENTERED);
375 | currentButtonStates[1] = 0;
376 | }
377 | if (dataArrayBit4[1] == 0 && (dataArrayBit7[1] != 0 && dataArrayBit6[1] != 0)) {
378 | //Serial.print(" U");
379 | bleGamepad.setHat1(DPAD_UP);
380 | currentButtonStates[1] = 1;
381 | }
382 | if (dataArrayBit5[1] == 0 && (dataArrayBit7[1] != 0 && dataArrayBit6[1] != 0)) {
383 | //Serial.print(" D");
384 | bleGamepad.setHat1(DPAD_DOWN);
385 | currentButtonStates[1] = 2;
386 | }
387 | if (dataArrayBit6[1] == 0 && (dataArrayBit4[1] != 0 && dataArrayBit5[1] != 0)) {
388 | //Serial.print(" L");
389 | bleGamepad.setHat1(DPAD_LEFT);
390 | currentButtonStates[1] = 3;
391 | }
392 | if (dataArrayBit7[1] == 0 && (dataArrayBit4[1] != 0 && dataArrayBit5[1] != 0)) {
393 | //Serial.print(" R");
394 | bleGamepad.setHat1(DPAD_RIGHT);
395 | currentButtonStates[1] = 4;
396 | }
397 | if (dataArrayBit4[1] == 0 && dataArrayBit6[1] == 0) {
398 | //Serial.print(" U/L");
399 | bleGamepad.setHat1(DPAD_UP_LEFT);
400 | currentButtonStates[1] = 5;
401 | }
402 | if (dataArrayBit4[1] == 0 && dataArrayBit7[1] == 0) {
403 | //Serial.print(" U/R");
404 | bleGamepad.setHat1(DPAD_UP_RIGHT);
405 | currentButtonStates[1] = 6;
406 | }
407 | if (dataArrayBit5[1] == 0 && dataArrayBit6[1] == 0) {
408 | //Serial.print(" D/L");
409 | bleGamepad.setHat1(DPAD_DOWN_LEFT);
410 | currentButtonStates[1] = 7;
411 | }
412 | if (dataArrayBit5[1] == 0 && dataArrayBit7[1] == 0) {
413 | //Serial.print(" D/R");
414 | bleGamepad.setHat1(DPAD_DOWN_RIGHT);
415 | currentButtonStates[1] = 8;
416 | }
417 | // End DPAD
418 |
419 | //Buttons
420 | if (dataArrayBit2[2] == 0) {
421 | Serial.print(" A");
422 | bleGamepad.press(BUTTON_4);
423 | currentButtonStates[3] = 1;
424 | } else {
425 | //Serial.print(" ");
426 | bleGamepad.release(BUTTON_4);
427 | currentButtonStates[3] = 0;
428 | }
429 | if (dataArrayBit0[2] == 0) {
430 | //Serial.print(" B");
431 | bleGamepad.press(BUTTON_1);
432 | currentButtonStates[4] = 1;
433 | } else {
434 | //Serial.print(" ");
435 | bleGamepad.release(BUTTON_1);
436 | currentButtonStates[4] = 0;
437 | }
438 | if (dataArrayBit1[2] == 0) {
439 | //Serial.print(" C");
440 | bleGamepad.press(BUTTON_2);
441 | currentButtonStates[5] = 1;
442 | } else {
443 | //Serial.print(" ");
444 | bleGamepad.release(BUTTON_2);
445 | currentButtonStates[5] = 0;
446 | }
447 | if (dataArrayBit6[2] == 0) {
448 | //Serial.print(" X");
449 | bleGamepad.press(BUTTON_7);
450 | currentButtonStates[6] = 1;
451 | } else {
452 | //Serial.print(" ");
453 | bleGamepad.release(BUTTON_7);
454 | currentButtonStates[6] = 0;
455 | }
456 | if (dataArrayBit5[2] == 0) {
457 | // Serial.print(" Y");
458 | bleGamepad.press(BUTTON_5);
459 | currentButtonStates[7] = 1;
460 | } else {
461 | //Serial.print(" ");
462 | bleGamepad.release(BUTTON_5);
463 | currentButtonStates[7] = 0;
464 | }
465 | if (dataArrayBit4[2] == 0) {
466 | //Serial.print(" Z");
467 | bleGamepad.press(BUTTON_8);
468 | currentButtonStates[8] = 1;
469 | } else {
470 | //Serial.print(" ");
471 | bleGamepad.release(BUTTON_8);
472 | currentButtonStates[8] = 0;
473 | }
474 | // Uncomment for L/R triggers to send digital in addition to analog values
475 | // May have wrong button_number defined here in the blegamepad.press setting
476 | //if (dataArrayBit3[3] == 0) {
477 | //Serial.print(" LT");
478 | // bleGamepad.press(BUTTON_5);
479 | // currentButtonStates[9] = 1;
480 | //} else {
481 | //Serial.print(" ");
482 | // bleGamepad.release(BUTTON_5);
483 | // currentButtonStates[9] = 0;
484 | //}
485 | //if (dataArrayBit7[2] == 0) {
486 | //Serial.print(" RT");
487 | // bleGamepad.press(BUTTON_6);
488 | // currentButtonStates[10] = 1;
489 | //} else {
490 | //Serial.print(" ");
491 | // bleGamepad.release(BUTTON_6);
492 | // currentButtonStates[10] = 1;
493 | //}
494 | if (dataArrayBit3[2] == 0) {
495 | //Serial.print(" Start ");
496 | bleGamepad.press(BUTTON_12);
497 | currentButtonStates[2] = 1;
498 | } else {
499 | bleGamepad.release(BUTTON_12);
500 | currentButtonStates[2] = 0;
501 | }
502 | // Latency Test Pin
503 | // Intended for BlueRetro latency button
504 | // Can be used for other additional buttons
505 | //
506 | // Note this sends "Start" but can be adjusted to press any other button
507 | if (digitalRead(latPin) == LOW) {
508 | //Serial.print("LAT");
509 | bleGamepad.press(BUTTON_3);
510 | currentButtonStates[3] = 1;
511 | } else {
512 | bleGamepad.release(BUTTON_3);
513 | currentButtonStates[3] = 0;
514 | }
515 |
516 | // Up / Down
517 | if (dataArrayBit7[4] == 1) {
518 | upDownValue = dataArrayBit0[5] + (dataArrayBit1[5]<<1) + (dataArrayBit2[5]<<2) + (dataArrayBit3[5]<<3) + (dataArrayBit4[4]<<4) + (dataArrayBit5[4]<<5) + (dataArrayBit6[4]<<6);
519 | //bleAnalogX = map(upDownValue, 0, 127, 1, 32767);
520 | bleAnalogX = map(upDownValue, 0, 127, 16384, 32767);
521 |
522 | } else {
523 | upDownValue = !dataArrayBit0[5] + (!dataArrayBit1[5]<<1) + (!dataArrayBit2[5]<<2) + (!dataArrayBit3[5]<<3) + (!dataArrayBit4[4]<<4) + (!dataArrayBit5[4]<<5) + (!dataArrayBit6[4]<<6);
524 | //bleAnalogX = map(upDownValue, 1, 127, -1, -32767);
525 | bleAnalogX = map(upDownValue, 0, 127, 16383, 1);
526 | }
527 | // Deadzone fix - X Axis
528 | // Value is checked based on map output
529 | //=======COMMENTED THIS OUT TEMPORARILY
530 | //if ((bleAnalogX < 0 && bleAnalogX > -500)||(bleAnalogX < 0 && bleAnalogX > -500)){
531 | // bleAnalogX = 0;
532 | // }
533 |
534 |
535 | //Analog Debugs
536 | //Serial.print(" bleAnalogX ");
537 | //Serial.println(bleAnalogX);
538 | // Format Value to 3 Chars long
539 | //char buf[] = "000";
540 | //sprintf(buf, "%03i", upDownValue);
541 |
542 | // Left / Right
543 | if (dataArrayBit7[3] == 1) {
544 | //Serial.print(" R = ");
545 | leftRightValue = dataArrayBit0[4] + (dataArrayBit1[4]<<1) + (dataArrayBit2[4]<<2) + (dataArrayBit3[4]<<3) + (dataArrayBit4[3]<<4) + (dataArrayBit5[3]<<5) + (dataArrayBit6[3]<<6);
546 | //bleAnalogY = map(leftRightValue, 1, 127, 1, 32767);
547 | bleAnalogY = map(leftRightValue, 0, 127, 16384, 32767);
548 | } else {
549 | leftRightValue = !dataArrayBit0[4] + (!dataArrayBit1[4]<<1) + (!dataArrayBit2[4]<<2) + (!dataArrayBit3[4]<<3) + (!dataArrayBit4[3]<<4) + (!dataArrayBit5[3]<<5) + (!dataArrayBit6[3]<<6);
550 |
551 | bleAnalogY = map(leftRightValue, 0, 127, 16383, 1);
552 | }
553 | //=======COMMENTED THIS OUT TEMPORARILY
554 | // Deadzone fix - Y Axis
555 | // Value is checked based on map output
556 | //if ((bleAnalogY > 0 && bleAnalogY < 500)||(bleAnalogY < 0 && bleAnalogY > -500)){
557 | // bleAnalogY = 0;
558 | //}
559 | // Set Analog Pad/Left Thumb Stick X Y Values in Blegamepad
560 | // This is an easy place to flip the X and Yresults if backwards for your use case
561 | bleGamepad.setX(bleAnalogY);
562 | bleGamepad.setY(bleAnalogX);
563 | // Track State of Analog Sticks X and Y Values
564 | currentButtonStates[11] = bleAnalogX;
565 | currentButtonStates[12] = bleAnalogY;
566 | //unused at this time
567 | //currentButtonStates[13] = 0;
568 | //currentButtonStates[14] = 0;
569 |
570 | // Decode Triggers
571 | char trbuf[] = "00";
572 | //Left Trigger
573 | ltValue = (dataArrayBit7[6] * 8) + (dataArrayBit6[6] * 4) + (dataArrayBit5[6] * 2) + (dataArrayBit4[6] * 1);
574 | //bleLTrigger = map(ltValue, 0, 15, -32767, 32767);
575 | bleLTrigger = map(ltValue, 0, 15, 1, 32767);
576 | bleGamepad.setLeftTrigger(bleLTrigger);
577 | //Track State of L trigger
578 | currentButtonStates[9] = bleLTrigger;
579 |
580 | //sprintf(trbuf, "%02i", ltValue);
581 | //Serial.print(" LT = ");
582 | //Serial.print(trbuf);
583 |
584 | //Right Trigger
585 | rtValue = (dataArrayBit7[5] * 8) + (dataArrayBit6[5] * 4) + (dataArrayBit5[5] * 2) + (dataArrayBit4[5] * 1);
586 | //bleRTrigger = map(rtValue, 0, 15, 32767, -32767);
587 | bleRTrigger = map(rtValue, 0, 15, 1, 32767);
588 | bleGamepad.setRightTrigger(bleRTrigger);
589 | //Track State of R trigger
590 | currentButtonStates[10] = bleRTrigger;
591 | //sprintf(trbuf, "%02i", rtValue);
592 | //Serial.print(" RT = ");
593 | //Serial.print(trbuf);
594 |
595 | //Debug
596 | unsigned int wMark1 = uxTaskGetStackHighWaterMark(nullptr);
597 | printf("Watermark before SendReportA loop is is %u\n", wMark1);
598 |
599 | //All Input states gathered Send Update if current and previous states do not match
600 | //bleGamepad.sendReport();
601 | if (currentButtonStates != previousButtonStates)
602 | {
603 | for (byte currentIndex = 0; currentIndex < numOfButtons; currentIndex++)
604 | {
605 | previousButtonStates[currentIndex] = currentButtonStates[currentIndex];
606 | }
607 |
608 | bleGamepad.sendReport();
609 | }
610 | //End all Analog Mode data
611 |
612 |
613 | } else {
614 | // Digital Mode - Process Input
615 | // ============================
616 |
617 | // DPAD
618 | if (dataArrayBit6[1] != 0 && dataArrayBit7[1] != 0 && dataArrayBit5[1] != 0 && dataArrayBit4[1] != 0){
619 | bleGamepad.setHat1(DPAD_CENTERED);
620 | currentButtonStates[1] = 0;
621 | }
622 | if (dataArrayBit4[0] == 0 && (dataArrayBit7[0] != 0 || dataArrayBit6[0] != 0)) {
623 | //Serial.print(" U ");
624 | bleGamepad.setHat1(DPAD_UP);
625 | currentButtonStates[1] = 1;
626 | }
627 | if (dataArrayBit5[0] == 0 && (dataArrayBit7[0] != 0 || dataArrayBit6[0] != 0)) {
628 | //Serial.print(" D ");
629 | bleGamepad.setHat1(DPAD_DOWN);
630 | currentButtonStates[1] = 2;
631 | }
632 | if (dataArrayBit6[0] == 0 && (dataArrayBit4[0] !=0 || dataArrayBit5[0] != 0)) {
633 | //Serial.print(" L ");
634 | bleGamepad.setHat1(DPAD_LEFT);
635 | currentButtonStates[1] = 3;
636 | }
637 | if (dataArrayBit7[0] == 0 && (dataArrayBit4[0] !=0 || dataArrayBit5[0] != 0)) {
638 | //Serial.print(" R ");
639 | bleGamepad.setHat1(DPAD_RIGHT);
640 | currentButtonStates[1] = 4;
641 | }
642 | if (dataArrayBit4[0] == 0 && dataArrayBit6[0] == 0) {
643 | //Serial.print(" U/L ");
644 | bleGamepad.setHat1(DPAD_UP_LEFT);
645 | currentButtonStates[1] = 5;
646 | }
647 | if (dataArrayBit4[0] == 0 && dataArrayBit7[0] == 0) {
648 | //Serial.print(" U/R ");
649 | bleGamepad.setHat1(DPAD_UP_RIGHT);
650 | currentButtonStates[1] = 6;
651 | }
652 | if (dataArrayBit5[0] == 0 && dataArrayBit6[0] == 0) {
653 | //Serial.print(" D/L ");
654 | bleGamepad.setHat1(DPAD_DOWN_LEFT);
655 | currentButtonStates[1] = 7;
656 | }
657 | if (dataArrayBit5[0] == 0 && dataArrayBit7[0] == 0) {
658 | //Serial.print(" D/R ");
659 | bleGamepad.setHat1(DPAD_DOWN_RIGHT);
660 | currentButtonStates[1] = 8;
661 | }
662 |
663 | //Buttons
664 | if (dataArrayBit2[1] == 0) {
665 | //Serial.print(" A ");
666 | bleGamepad.press(BUTTON_4);
667 | currentButtonStates[3] = 1;
668 | } else {
669 | bleGamepad.release(BUTTON_4);
670 | currentButtonStates[3] = 0;
671 | }
672 | if (dataArrayBit0[1] == 0) {
673 | //Serial.print(" B ");
674 | bleGamepad.press(BUTTON_1);
675 | currentButtonStates[4] = 1;
676 | } else {
677 | bleGamepad.release(BUTTON_1);
678 | currentButtonStates[4] = 0;
679 | }
680 | if (dataArrayBit1[1] == 0) {
681 | //Serial.print(" C ");
682 | bleGamepad.press(BUTTON_2);
683 | currentButtonStates[5] = 1;
684 | } else {
685 | bleGamepad.release(BUTTON_2);
686 | currentButtonStates[5] = 0;
687 | }
688 | if (dataArrayBit6[1] == 0) {
689 | //Serial.print(" X ");
690 | bleGamepad.press(BUTTON_7);
691 | currentButtonStates[6] = 1;
692 | } else {
693 | bleGamepad.release(BUTTON_7);
694 | currentButtonStates[6] = 0;
695 | }
696 | if (dataArrayBit5[1] == 0) {
697 | //Serial.print(" Y ");
698 | bleGamepad.press(BUTTON_5);
699 | currentButtonStates[7] = 1;
700 | } else {
701 | bleGamepad.release(BUTTON_5);
702 | currentButtonStates[7] = 0;
703 | }
704 | if (dataArrayBit4[1] == 0) {
705 | //Serial.print(" Z ");
706 | bleGamepad.press(BUTTON_8);
707 | currentButtonStates[8] = 1;
708 | } else {
709 | bleGamepad.release(BUTTON_8);
710 | currentButtonStates[8] = 0;
711 | }
712 | if (dataArrayBit3[2] == 0) {
713 | //Serial.print(" LT ");
714 | bleGamepad.press(BUTTON_11);
715 | currentButtonStates[9] = 1;
716 | } else {
717 | bleGamepad.release(BUTTON_11);
718 | currentButtonStates[9] = 0;
719 | }
720 | if (dataArrayBit7[1] == 0) {
721 | //Serial.print(" RT ");
722 | bleGamepad.press(BUTTON_13);
723 | currentButtonStates[10] = 1;
724 | } else {
725 | bleGamepad.release(BUTTON_13);
726 | currentButtonStates[10] = 0;
727 | }
728 | if (dataArrayBit3[1] == 0) {
729 | //Serial.println(" Start ");
730 | bleGamepad.press(BUTTON_12);
731 | currentButtonStates[2] = 1;
732 | } else {
733 | ////Serial.println(" ");
734 | bleGamepad.release(BUTTON_12);
735 | currentButtonStates[2] = 0;
736 | }
737 | // Latency Test Pin
738 | // Intended for BlueRetro latency test pad to measure BLEGamepad update speeds without modifying the Controller
739 | if (digitalRead(latPin) == LOW) {
740 | Serial.print("Latency Test Press");
741 | bleGamepad.press(BUTTON_3);
742 | currentButtonStates[2] = 1;
743 | } else {
744 | bleGamepad.release(BUTTON_3);
745 | currentButtonStates[2] = 0;
746 | }
747 |
748 | // unsigned int wMark2 = uxTaskGetStackHighWaterMark(nullptr);
749 | // printf("Watermark - SendReport B loop %u\n", wMark2);
750 |
751 | // All Input states gathered Send Update if state has changed
752 | if (currentButtonStates != previousButtonStates){
753 | for (byte currentIndex = 0; currentIndex < numOfButtons; currentIndex++)
754 | {
755 | previousButtonStates[currentIndex] = currentButtonStates[currentIndex];
756 | }
757 | bleGamepad.sendReport();
758 | }
759 | }
760 | // End Digital Mode - Process Input
761 | // ================================
762 |
763 |
764 | // Invalid Data or no connection error state
765 | // =========================================
766 | // Communication or wiring issue
767 | } else {
768 | for (int printByteCounter = 0; printByteCounter < modeCounter + 1; printByteCounter++) {
769 | int derpvar;
770 | derpvar=0;
771 | //Serial.println("Error: Gamepad may not be paired OR Pinout/Timing Incorrect");
772 | //Uncomment lines for additional debug output
773 | //Serial.print(" -- Byte ");
774 | //Serial.print(printByteCounter);
775 | //Serial.print(" - ");
776 | //Serial.print(dataArrayBit0[printByteCounter]);
777 | //Serial.print(dataArrayBit1[printByteCounter]);
778 | //Serial.print(dataArrayBit2[printByteCounter]);
779 | //Serial.print(dataArrayBit3[printByteCounter]);
780 | //Serial.print(dataArrayBit4[printByteCounter]);
781 | //Serial.print(dataArrayBit5[printByteCounter]);
782 | //Serial.print(dataArrayBit6[printByteCounter]);
783 | //Serial.print(dataArrayBit7[printByteCounter]);
784 | }
785 | // End Invalid Data
786 | //=================
787 | }
788 | // End Polling
789 | // ===========
790 |
791 | // Reset variables ready for data read.
792 | byteCounter = 0;
793 | nibble0Read = 0;
794 |
795 | // Setting Current Time for data read
796 | timeStamp = millis();
797 | }
798 |
799 |
800 | // Check to see if the Controller is ready to send data and if we have read any data yet
801 | if (TLACK == HIGH and nibble0Read == 0) {
802 | digitalWrite(THPin, LOW);
803 | delayMicroseconds(4); // I don't think I need this
804 | digitalWrite(TRPin, LOW);
805 | delayMicroseconds(4);
806 | //delayMicroseconds(1);
807 | }
808 |
809 |
810 | // If the 1st nibble is being sent and we havn't read the 1st nibble yet get the data from the pins
811 | if (TLACK == LOW and nibble0Read == 0) {
812 | // Sets ready to read the 1st nibble of data
813 | digitalWrite(TRPin, HIGH);
814 | delayMicroseconds(8); //For ESP32 with lower setting get random button press
815 |
816 | // Read the Data for the 1st Nibble
817 | dataArrayBit0[byteCounter] = digitalRead(dataPinD0);
818 | dataArrayBit1[byteCounter] = digitalRead(dataPinD1);
819 | dataArrayBit2[byteCounter] = digitalRead(dataPinD2);
820 | dataArrayBit3[byteCounter] = digitalRead(dataPinD3);
821 |
822 | if (dataArrayBit0[byteCounter] > 1) {
823 | dataArrayBit0[byteCounter] = 0;
824 | }
825 | if (dataArrayBit1[byteCounter] > 1) {
826 | dataArrayBit1[byteCounter] = 0;
827 | }
828 | if (dataArrayBit2[byteCounter] > 1) {
829 | dataArrayBit2[byteCounter] = 0;
830 | }
831 | if (dataArrayBit3[byteCounter] > 1) {
832 | dataArrayBit3[byteCounter] = 0;
833 | }
834 |
835 | // 1st Nibble has been read
836 | nibble0Read = 1;
837 |
838 | // Check if we are reading data for Analogue mode or Digital Mode
839 | // The mode defines the number of Bytes we need to read
840 | if (byteCounter == 0) {
841 | if ((dataArrayBit0[0] == 1 and dataArrayBit1[0] == 0 and dataArrayBit2[0] == 0 and dataArrayBit3[0] == 0) or (dataArrayBit0[0] == 0 and dataArrayBit1[0] == 1 and dataArrayBit2[0] == 1 and dataArrayBit3[0] == 0) or (dataArrayBit0[0] == 1 and dataArrayBit1[0] == 1 and dataArrayBit2[0] == 1 and dataArrayBit3[0] == 0) ) {
842 | modeCounter = AnalogMode;
843 | } else {
844 | modeCounter = DigitalMode;
845 | }
846 | }
847 | }
848 |
849 | // Check if the 2nd Nibble is being sent and if we have already read the 1st Nibble
850 | if (TLACK == HIGH and nibble0Read == 1) {
851 | // Sets ready to read the 2nd Nibble
852 | digitalWrite(TRPin, LOW);
853 | delayMicroseconds(8);
854 | // Read the data for the 2nd Nibble
855 | dataArrayBit4[byteCounter] = digitalRead(dataPinD0);
856 | dataArrayBit5[byteCounter] = digitalRead(dataPinD1);
857 | dataArrayBit6[byteCounter] = digitalRead(dataPinD2);
858 | dataArrayBit7[byteCounter] = digitalRead(dataPinD3);
859 | if (dataArrayBit4[byteCounter] > 1) {
860 | dataArrayBit4[byteCounter] = 0;
861 | }
862 | if (dataArrayBit5[byteCounter] > 1) {
863 | dataArrayBit5[byteCounter] = 0;
864 | }
865 | if (dataArrayBit6[byteCounter] > 1) {
866 | dataArrayBit6[byteCounter] = 0;
867 | }
868 | if (dataArrayBit7[byteCounter] > 1) {
869 | dataArrayBit7[byteCounter] = 0;
870 | }
871 |
872 | // Reset the 1st Nibble read variable, ready for the next Byte of data
873 | nibble0Read = 0;
874 |
875 | // Increase the Byte counter by 1 so we are ready to read the next Byte of data
876 | byteCounter++;
877 | }
878 |
879 | // Time Stamp Routines to check if data has paused.
880 | currentMillis = millis();
881 |
882 | if (currentMillis - timeStamp >= interval) {
883 | // Resetting All Variables
884 | timeStamp = millis();
885 | digitalWrite(THPin, HIGH);
886 | digitalWrite(TRPin, HIGH);
887 | byteCounter = 0;
888 | nibble0Read = 0;
889 | Serial.println("Resetting");
890 | }
891 | }
892 | //=============================
893 | // End Controller related items
894 |
895 | // Pin anything that isn't the controller or bluetooth to core 0
896 | //==============================================================
897 |
898 | void Task1code( void * pvParameters ){
899 | //Serial.print("OLED Update ESP Core ");
900 | //Serial.println(xPortGetCoreID());
901 |
902 | for(;;){
903 | //Serial.print("timeStamp val" );
904 | if (timeStamp == 0){
905 | //bootLogo();
906 | timeStamp = 1;
907 | }
908 | //oled_Updates();
909 | //getBatStat();
910 | Serial.print(" ");
911 | }
912 | }
913 | // End Core Pinning
914 | //=================
915 |
916 |
917 | // Controller and Bluetooth Jobs here
918 | void Task2code( void * pvParameters ){
919 | //Serial.print("Task2code running on core ");
920 | //Serial.println(xPortGetCoreID());
921 |
922 | for(;;){
923 | //debug
924 | // unsigned int wMark3 = uxTaskGetStackHighWaterMark(nullptr);
925 | // printf("Watermark before FOR Loop is %u\n", wMark3);
926 |
927 | pollController();
928 | //debug
929 | // unsigned int wMark = uxTaskGetStackHighWaterMark(nullptr);
930 | // printf("Watermark after FOR Loop is %u\n", wMark);
931 | }
932 | }
933 |
934 |
935 | // This is the main loop due to threading in arduino + core tasking in RTOS
936 | //==========================================================================
937 | void setup() {
938 | // Check ESP Core
939 | //Serial.print("Setup Core");
940 | //Serial.println(xPortGetCoreID());
941 |
942 |
943 | // Start BLE Gamepad
944 | BleGamepadConfiguration bleGamepadConfig;
945 | bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD); // CONTROLLER_TYPE_JOYSTICK, CONTROLLER_TYPE_GAMEPAD (DEFAULT), CONTROLLER_TYPE_MULTI_AXIS
946 | bleGamepadConfig.setButtonCount(numOfButtons);
947 | bleGamepadConfig.setWhichAxes(enableX, enableY, enableZ, enableRX, enableRY, enableRZ, enableSlider1, enableSlider2); // Can also be done per-axis individually. All are true by default
948 | bleGamepadConfig.setHatSwitchCount(numOfHatSwitches); // 1 by default
949 | bleGamepadConfig.setAxesMin(0x8001); // -32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
950 | //
951 | //bleGamepadConfig.setAxesMin(0x0001); // -32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
952 | bleGamepadConfig.setAxesMax(0x7FFF); // 32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
953 | // Other Available Special Button Options
954 | // bleGamepadConfig.setIncludeStart(true);
955 | // bleGamepadConfig.setIncludeSelect(true);
956 | // bleGamepadConfig.setIncludeMenu(true);
957 | // bleGamepadConfig.setIncludeHome(true);
958 | // bleGamepadConfig.setIncludeBack(true);
959 | // bleGamepadConfig.setIncludeVolumeInc(true);
960 | // bleGamepadConfig.setIncludeVolumeDec(true);
961 | // bleGamepadConfig.setIncludeVolumeMute(true);
962 | // Use or disable BLEGampead AutoReporting
963 | // AutoReport can impact latency negatively with high speed of updates
964 | bleGamepadConfig.setAutoReport(false); // This is true by default
965 | bleGamepad.begin(&bleGamepadConfig);
966 |
967 |
968 | // Setting input and output pins for Comms with Controller
969 | // Use Heavy and Lightwing pinout settings instead of changing this
970 | //==========================// Pin 1 = +5V
971 | pinMode(dataPinD1, INPUT); // Pin 2 = Data D1
972 | pinMode(dataPinD0, INPUT); // Pin 3 = Data D0
973 | pinMode(THPin, OUTPUT); // Pin 4 = TH Select
974 | pinMode(TRPin, OUTPUT); // Pin 5 = TR Request
975 | pinMode(TLPin, INPUT); // Pin 6 = TL Response
976 | pinMode(dataPinD3, INPUT); // Pin 7 = Data D3
977 | pinMode(dataPinD2, INPUT); // Pin 8 = Data D2
978 | //==========================// Pin 9 = GND
979 |
980 | // Set pin state to begin reading controller state
981 | digitalWrite(THPin, HIGH);
982 | digitalWrite(TRPin, HIGH);
983 |
984 | // Define Latency test pin
985 | pinMode(latPin,INPUT_PULLUP );
986 |
987 |
988 | // Setup Serial comms for Serial Monitor
989 | Serial.begin(115200);
990 | Serial.print("Device Booting....");
991 |
992 | // Creates Tasks for Core 0
993 | xTaskCreatePinnedToCore(
994 | Task1code, /* Task function. */
995 | "Task1", /* name of task. */
996 | 5000, /* Stack size of task */ //originally 10k
997 | NULL, /* parameter of the task */
998 | 3, /* priority of the task */
999 | &Task1, /* Task handle to keep track of created task */
1000 | 0); /* pin task to core 0 */
1001 |
1002 | //Creates Tasks for Core 0
1003 | xTaskCreatePinnedToCore(
1004 | Task2code, /* Task function. */
1005 | "Task2", /* name of task. */
1006 | 5000, /* Stack size of task */
1007 | NULL, /* parameter of the task */
1008 | 2, /* priority of the task */
1009 | &Task2, /* Task handle to keep track of created task */
1010 | 1); /* pin task to core 1 */
1011 |
1012 | }
1013 |
1014 |
1015 | // Loop will always run on Core 1
1016 | void loop(){
1017 | // Putting stuff here will break some automatic aspects of RTOS task cleanup
1018 | // All tasks/jobs should be performed from setup loop
1019 | }
1020 |
1021 | //Currently unused setup for Motion Controls
1022 | // All this code is trashed and intermixed (sorry) but the idea is
1023 | // initializeSensor -> setupMPU -> GetTiltMpu
1024 | void initializeSensor(){
1025 | // Perfrom full reset as per MPU-6000/MPU-6050 Register Map and Descriptions, Section 4.28, pages 40 to 41.
1026 | // performing full device reset, disables temperature sensor, disables SLEEP mode
1027 | Wire.beginTransmission(0x68); // Device address.
1028 | Wire.write(0x6B); // PWR_MGMT_1 register.
1029 | Wire.write(0b10001000); // DEVICE_RESET, TEMP_DIS.
1030 | Wire.endTransmission();
1031 | delay(100); // Wait for reset to complete.
1032 |
1033 | Wire.beginTransmission(0x68); // Device address.
1034 | Wire.write(0x68); // SIGNAL_PATH_RESET register.
1035 | Wire.write(0b00000111); // GYRO_RESET, ACCEL_RESET, TEMP_RESET.
1036 | Wire.endTransmission();
1037 | delay(100); // Wait for reset to complete.
1038 |
1039 | // Disable SLEEP mode because the reset re-enables it. Section 3, PWR_MGMT_1 register, page 8.
1040 | Wire.beginTransmission(MPU_addr); // Device address.
1041 | Wire.write(0x6B); // PWR_MGMT_1 register.
1042 | Wire.write(0b00001000); // SLEEP = 0, TEMP_DIS = 1.
1043 | Wire.endTransmission();
1044 | }
1045 | // =============
1046 | // End Start MPU
1047 |
1048 | void setupMPU() {
1049 | //Setup Accelerometer
1050 | //Wire.begin();
1051 |
1052 | //Configure MPU Connectivity
1053 | //Wire.beginTransmission(MPU_addr);
1054 | //Wire.write(0x68);
1055 | //Wire.write(0x00); // Make reset - place a 0 into the 6B register
1056 | //Wire.endTransmission(true);
1057 | //Wire.write(0);
1058 | //Wire.endTransmission(true);
1059 |
1060 |
1061 | //Adafruit_MPU6050 mpu;
1062 | //if (!Wire.begin()) {
1063 | // Serial.println("Failed to find MPU6050 chip");
1064 | // while (1) {
1065 | // delay(10);
1066 | // }
1067 | //}
1068 | //Serial.println("MPU6050 Found!");
1069 | //Setup Accelerometer End
1070 | }
1071 |
1072 |
1073 |
1074 | void getTiltMPU() {
1075 | //sensors_event_t a, g, temp;
1076 | //mpu.getEvent(&a, &g, &temp);
1077 | //Wire.begin();
1078 |
1079 | //Configure MPU Connectivity
1080 | //Wire.beginTransmission(MPU_addr);
1081 | //Wire.write(0x68);
1082 | //Wire.write(0);
1083 | //Wire.endTransmission(true);
1084 |
1085 | //Serial.begin(115200);
1086 | //void loop(){
1087 |
1088 | //Get Data from MPU
1089 | //Wire.beginTransmission(MPU_addr);
1090 | //Wire.write(0x3B);
1091 | //Wire.endTransmission(false);
1092 | //Wire.requestFrom(MPU_addr,14,true);
1093 |
1094 | //Store MPU Values
1095 | //AcX=Wire.read()<<8|Wire.read();
1096 | //AcY=Wire.read()<<8|Wire.read();
1097 | //AcZ=Wire.read()<<8|Wire.read();
1098 |
1099 | Serial.print("MPU X Y Z");
1100 | //Serial.print(a.acceleration.x, 1);
1101 | //Serial.print(a.acceleration.y, 1);
1102 | //Serial.print(a.acceleration.z, 1);
1103 | Serial.print("MPU GYRO");
1104 | //Serial.print(g.gyro.x, 1);
1105 | //Serial.print(g.gyro.y, 1);
1106 | //Serial.print(g.gyro.z, 1);
1107 |
1108 | //Convert stored values from Rads to Degrees
1109 | //int xAng = map(AcX,minVal,maxVal,-90,90);
1110 | //int yAng = map(AcY,minVal,maxVal,-90,90);
1111 | //int zAng = map(AcZ,minVal,maxVal,-90,90);
1112 | //x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);
1113 | //y= RAD_TO_DEG * (atan2(-xAng, -zAng)+PI);
1114 | //z= RAD_TO_DEG * (atan2(-yAng, -xAng)+PI);
1115 |
1116 | //Print current angles
1117 | //Serial.print("AngleX ");
1118 | //Serial.println(x);
1119 | //Serial.print("AngleY ");
1120 | //Serial.println(y);
1121 | //display.clearDisplay();
1122 | //display.setTextSize(1); // Normal 1:1 pixel scale
1123 | //display.setTextColor(SSD1306_WHITE, BLACK); // Draw white text
1124 | //display.setCursor(0,10);
1125 | //display.println("Tilt: On");
1126 | //display.setCursor(0,20); // r
1127 | //String derp1 = " X Axis: " + String(x);
1128 | //String derp2 = " Y Axis: " + String(y);
1129 | //display.clearDisplay();
1130 | //display.println(derp1);
1131 | //display.println(F("X Axis " + String(x)));
1132 | //display.setCursor(0,30);
1133 | //display.println(derp2);
1134 | //display.println(F("y Axis " + String(y)));
1135 | //display.display();
1136 | //
1137 |
1138 | //Limit Degrees of angle based on comfort prior to converting to BLEGamepad Vals
1139 | //Limit X
1140 | if (x < 160){
1141 | x=160;
1142 | }
1143 | if (x > 200){
1144 | x=200;
1145 | }
1146 | //Limit Y
1147 | if (y < 160){
1148 | y=160;
1149 | }
1150 | if (y > 200){
1151 | y=200;
1152 | }
1153 |
1154 | //Define DeadZones
1155 | //Will require calibration based on your install
1156 | //
1157 | //Create X deadzone
1158 | if ((x >= 170) && (x <= 190)){
1159 | x=180;
1160 | }
1161 | //
1162 | //Create Y deadzone
1163 | if ((y >= 170) && (y <= 190)){
1164 | y=180;
1165 | }
1166 |
1167 | //Map Values to Gamepad Ranges
1168 | xmap = map (x, 160, 200, 0, 32767);
1169 | ymap = map (y, 160, 200, 0, 32767);
1170 | //Print Mapped values
1171 | //Serial.print("Xmap BleG: ");
1172 | //Serial.println(xmap);
1173 | //Serial.print("Ymap BleG: ");
1174 | //Serial.println(ymap);
1175 |
1176 | Serial.println("-----------------------------------------");
1177 |
1178 | }
1179 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | // Add BLE Gamepad
4 | #include
5 | // Add OLED
6 | #include
7 | #include
8 | // Add Adafruit Sensor Libs for Tilt Controls
9 | #include
10 | #include
11 |
12 | //====================================================
13 | // __________.____ ___________.________ _________
14 | // \______ \ | \_ _____/ \_____ \\______ \
15 | // | | _/ | | __)_ _(__ < | | \
16 | // | | \ |___ | \ / \| ` \
17 | // |______ /_______ \/_______ / /______ /________ /
18 | // \/ \/ \/ \/ \/
19 | // Greetz and massive thanks to Hexfreq for being a complete bad ass
20 | //
21 | // All reliable controller code foundation is from [at]Hexfreq
22 | // All bugs, poor code choices, and existing PCB designs courtesy of [at]GamingNJncos
23 | // Cheers to [at]Arthrimus for lighting this fire on accident
24 | //
25 | // As I have limited time for mainting this codebase long term attempts have been made to over document code provided
26 | // No Warranty expressed or implied
27 | //====================================================
28 |
29 |
30 | // OLED Screen Settings
31 | #define SCREEN_WIDTH 128 // OLED display width, in pixels
32 | #define SCREEN_HEIGHT 64 // OLED display height, in pixels
33 | #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
34 | #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
35 | Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
36 |
37 | // Establish tasks for ESP32 CPU Core Pinning
38 | TaskHandle_t Task1;
39 | TaskHandle_t Task2;
40 |
41 | // BLEGamePad Settings
42 | // ===================
43 | // Values are Advertised Name, Manufacturer, Battery level
44 | // Note the battery value is not from a read value here but later blegamepad examples support live update vs 1 time poll
45 | BleGamepad bleGamepad("Reala", "GamingNJncos.HexFreq", 100);
46 | // Purposely set high to permit ease of future additional button combinationsfor to send Meta, home button, etc
47 | #define numOfButtons 12
48 | #define numOfHatSwitches 1 //DPAD (not Analog pad)
49 | #define enableX true // Analog Pad
50 | #define enableY true // Analog Pad
51 | #define enableRX true // Triggers
52 | #define enableRY true // Triggers
53 | // Additional button options currently disabled
54 | #define enableZ false
55 | #define enableRZ false
56 | #define enableSlider1 false
57 | #define enableSlider2 false
58 | #define enableRudder false
59 | #define enableThrottle false
60 | #define enableAccelerator false
61 | #define enableBrake false
62 | #define enableSteering false
63 | // End BLEGamePad Settings
64 |
65 | // Button State Tracking
66 | // This nets a significant advantage in performance vs not tracking states
67 | // BLE expects ACK per packet so flooding "not pressed" or identical data can add extreme delays
68 | //
69 | byte previousButtonStates[12];
70 | byte currentButtonStates[12];
71 | // Button State Array Map
72 | // ======================
73 | // MODE, DPAD, START, A, B, C, X, Y, Z, L, R, Analog PAD
74 | // [0-1] [0-8] [- Binary Values 0-1 -] [0-15] [0-127,0-127]
75 | // Note Left and Right stick in digital mode will return Binary [0-1] vs [0-15] value in analog mode
76 |
77 | // Pinmappings for your PCB version
78 | // It is manditory you select the correct pinout for your board type
79 |
80 | // Feather HeavyWing to Controller Pin Mapping
81 | // ===========================================
82 | //PCB: https://oshpark.com/shared_projects/ki7HbZV4
83 | //
84 | //int dataPinD0 = 32; // Arthrimus Pin 3 = Data D0
85 | //int dataPinD1 = 14; // Arthrimus Pin 2 = Data D1
86 | //int dataPinD2 = 13; // Arthrimus Pin 8 = Data D2
87 | //int dataPinD3 = 12; // Arthrimus Pin 7 = Data D3
88 | //int THPin = 15; // Arthrimus Pin 4 = TH Select
89 | //int TRPin = 33; // Arthrimus Pin 5 = TR Request
90 | //int TLPin = 27; // Arthrimus Pin 6 = TL Response
91 | //int batPin = A13; // Used by BLEGamepad library
92 | //int latPin = 4; // Latency testing pin
93 | // End Feather HeavyWing to Controller Pin Mapping
94 |
95 |
96 | // Feather LightWing to Controller Pin Mapping
97 | // ===========================================
98 | // PCB: https://oshpark.com/shared_projects/7RqwDWJT
99 | //
100 | int dataPinD0 = 12; // Arthrimus Pin 3 = Data D0
101 | int dataPinD1 = 13; // Arthrimus Pin 2 = Data D1
102 | int dataPinD2 = 14; // Arthrimus Pin 8 = Data D2
103 | int dataPinD3 = 32; // Arthrimus Pin 7 = Data D3
104 | int THPin = 27; // Arthrimus Pin 4 = TH Select
105 | int TRPin = 33; // Arthrimus Pin 5 = TR Request
106 | int TLPin = 15; // Arthrimus Pin 6 = TL Response
107 | int batPin = A13; // Used by BLEGamepad library
108 | int latPin = 4; // Latency testing pin
109 | // End Feather HeavyWing to Controller Pin Mapping
110 | // End all Pin Mappings
111 |
112 | // BleGamepad Variables
113 | // ====================
114 | int16_t bleAnalogX; //Analog pad X Axis Output
115 | int16_t bleAnalogY; //Analog pad Y Axis Output
116 | // DeadZone defined as smallest value to exceed before sending in blegamepad report function
117 | int16_t bleDeadZone = 400; //Set Deadzone via minimum number
118 | // Analog Triggers
119 | int16_t bleRTrigger; //Right Trigger Analog Output
120 | int16_t bleLTrigger; //Left Trigger Analog Output
121 | // Battery Monitoring variables for BLEGamepad
122 | // Note BLE Gamepad can read battery percent but can not check to transmit value after initial connection
123 | int adcRead = 0;
124 | int batVolt = 0;
125 | // End BleGamepad Variables
126 |
127 |
128 | // Controller protocol and timing variables
129 | // ========================================
130 | // Data Array for each byte from protocol
131 | boolean dataArrayBit0[8];
132 | boolean dataArrayBit1[8];
133 | boolean dataArrayBit2[8];
134 | boolean dataArrayBit3[8];
135 | boolean dataArrayBit4[8];
136 | boolean dataArrayBit5[8];
137 | boolean dataArrayBit6[8];
138 | boolean dataArrayBit7[8];
139 | // Assorted Protocol Variables
140 | int nibble0Read = 0; // Confirm 1st Nibble has been read
141 | int byteCounter = 0; // Current Byte Tracker
142 | int modeCounter = 4; // Reference for which mode we are currently in Analogue or Digital
143 | int DecodeData = 1; // Controller Successfully Decoded Data Variable
144 | int curMode = 0; // This stores the Controller Mode to pass between ESP cores
145 | // Assorted timing oriented variables
146 | unsigned long timeStamp = 0; // Store time of last update
147 | unsigned long lastTimeStamp = 0; // Store Last time for comparison
148 | const long interval = 1000; // Data update check timing
149 | unsigned long currentMillis = millis(); // check timing
150 | // Directional Variables
151 | int upDownValue = 0;
152 | int leftRightValue = 0;
153 | // Trigger Variables
154 | int ltValue = 0;
155 | int rtValue = 0;
156 | // Variables for Data send request and Acknowledgments
157 | int THSEL = 0;
158 | int TRREQ = 0;
159 | int TLACK = 0;
160 | // Sets the number of Bytes required for Digital or Analogue Modes
161 | int AnalogMode = 6;
162 | int DigitalMode = 3;
163 | // End Controller protocol and timing variables
164 |
165 |
166 | // Gyro and Accelerometer Variables
167 | // =================================
168 | // Gyro is currently disabled in code but my terrible examples should be useful if you wish to use this feature
169 | const int MPU_addr=0x68; // Define Gyro I2C Address
170 | int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; // Store all values from MPU
171 | int minVal=265;
172 | int maxVal=402;
173 | double x;
174 | double y;
175 | double z;
176 | // Converted XY Values to BLEGamepad ranges (negative to positive 32K
177 | int xmap;
178 | int ymap;
179 | // Max Values to limit full range of 360 degree motion.
180 | // Will require calibration with your MPU-6050 to identify most comfortable ranges
181 | // Suggest 35-45 Degrees or less relatively comfortable for most use cases
182 | int xmax = 200;
183 | int ymax = 200;
184 | int xmin = 160;
185 | int ymin = 160;
186 | // End Gyro and Accelerometer Variables
187 |
188 |
189 | // Boot Logo
190 | // ==========
191 | //Set Image Size for Boot Logo
192 | #define imageWidth 128
193 | #define imageHeight 64
194 | // Image to be displayed
195 | // These can be changed and alternatively set as animations
196 | // Create with "LCD Image Converter" tool or similar
197 | // https://lcd-image-converter.riuson.com/en/about/
198 | const unsigned char myBitmap [] PROGMEM=
199 | {
200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 | 0x0F, 0xFE, 0x0C, 0x00, 0xF6, 0x0C, 0x3C, 0x00, 0x60, 0x41, 0x80, 0x87, 0xFF, 0xF1, 0x80, 0x1E,
210 | 0x1E, 0x3F, 0xFB, 0xE7, 0x9E, 0x0E, 0x3E, 0x00, 0xE7, 0xBE, 0x7F, 0x03, 0xBF, 0x1E, 0xE0, 0x0E,
211 | 0x3C, 0x03, 0xE0, 0x7E, 0x03, 0x1E, 0x3E, 0x00, 0xE4, 0x1E, 0x0F, 0x03, 0x1E, 0x1E, 0x78, 0x0C,
212 | 0x3E, 0x01, 0xE0, 0x1E, 0x01, 0x1E, 0x3E, 0x01, 0xF0, 0x1E, 0x0F, 0x03, 0x1E, 0x0F, 0x3C, 0x0C,
213 | 0x3F, 0x01, 0xE1, 0x3E, 0x00, 0x3F, 0x1F, 0x03, 0xF0, 0x1E, 0x0F, 0x03, 0x1E, 0x0F, 0x3F, 0x0C,
214 | 0x1F, 0xC1, 0xE3, 0x3C, 0x00, 0x3D, 0x1F, 0x03, 0xD8, 0x1E, 0x0F, 0x03, 0x1E, 0x1E, 0x3F, 0x8C,
215 | 0x0F, 0xF1, 0xFF, 0x3C, 0x00, 0x79, 0x9F, 0x87, 0xD8, 0x1E, 0x0F, 0x03, 0x1E, 0x3E, 0x3F, 0xCC,
216 | 0x03, 0xF9, 0xFF, 0x3C, 0x00, 0xF9, 0x8F, 0x87, 0x8C, 0x1E, 0x0F, 0x03, 0x1E, 0xF0, 0x27, 0xEC,
217 | 0x00, 0xFD, 0xE3, 0x3C, 0x1F, 0xF0, 0xCF, 0xCF, 0x8C, 0x1E, 0x0F, 0x03, 0x1E, 0x78, 0x31, 0xFC,
218 | 0x40, 0x7D, 0xE0, 0x3E, 0x0F, 0xF0, 0xC7, 0xCF, 0x06, 0x1E, 0x0F, 0x03, 0x1E, 0x78, 0x30, 0xFC,
219 | 0x60, 0x3D, 0xE0, 0x3E, 0x07, 0xE0, 0x67, 0xDF, 0x06, 0x1E, 0x0F, 0x03, 0x1E, 0x3C, 0x30, 0x7C,
220 | 0x30, 0x3D, 0xE0, 0x7E, 0x07, 0xE0, 0x63, 0xFE, 0x03, 0x1E, 0x07, 0x87, 0x1E, 0x3E, 0x30, 0x3C,
221 | 0x3E, 0xF9, 0xF3, 0xFF, 0x0F, 0xE0, 0x73, 0xFE, 0x07, 0xBE, 0x07, 0xFE, 0x1F, 0x1F, 0x30, 0x0C,
222 | 0x1F, 0xE3, 0xFF, 0xE3, 0xFF, 0xE0, 0xFB, 0xFE, 0x07, 0xFF, 0x01, 0xF8, 0x3F, 0x87, 0xF0, 0x04,
223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
232 | };
233 | // End Boot Logo
234 |
235 |
236 | // Boot Logo and Screen Setup
237 | // ==========================
238 | void bootLogo(){
239 | //Check ESP Core Boot Logo is running on
240 | //Serial.print("BootLogo Core ");
241 | //Serial.println(xPortGetCoreID());
242 |
243 | if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
244 | Serial.println(F("SSD1306 allocation failed"));
245 | for(;;); // Don't proceed, loop forever
246 | }
247 | // Rotate
248 | display.setRotation(2);
249 | // Clear the Buffer
250 | display.clearDisplay();
251 | // Draw Animation
252 | // Draw Bitmap syntax
253 | // display.drawBitmap(x position, y position, bitmap data, bitmap width, bitmap height, color)
254 | display.drawBitmap(0, 32, myBitmap, 128, 32, WHITE);
255 | display.display();
256 | // Set Delay for Boot Animation
257 | delay(1500);
258 | // Reset Display
259 | display.display();
260 | display.setRotation(2);
261 | delay(10);
262 | // Clear the buffer
263 | display.clearDisplay();
264 | delay(2000);
265 | //End Screen Setup
266 | }
267 |
268 |
269 | // Battery Related Checks
270 | // ======================
271 | void getBatStat(){
272 | // Check ESP Core
273 | //Serial.print("Battery Status Core ");
274 | //Serial.println(xPortGetCoreID());
275 |
276 | adcRead = analogRead(batPin);
277 | batVolt = adcRead;
278 | // Multiply by 2 to correct reading for Featherwing Huzzah32
279 | //batVolt = adcRead * 2;
280 |
281 | int BatteryPct;
282 | int oldBatPct = 0;
283 | // Map Battery voltage range to a percentage
284 | BatteryPct = map (batVolt, 1200, 4200, 0, 100);
285 | // Make sure its populated on initial run
286 | if (oldBatPct < 1){
287 | oldBatPct = BatteryPct;
288 | }
289 | // Super hack check to omit negative values from OLED Updates
290 | if (BatteryPct < 0 ){
291 | BatteryPct = oldBatPct;
292 | }
293 |
294 | // Build and send screen update
295 | // ============================
296 | String lcdBat;
297 | lcdBat = "Battery: " + String(BatteryPct) + "% ";
298 | //display.setCursor(0,50);
299 | //display.print("Battery ");
300 | //display.setCursor(0,50);
301 | //display.print(lcdBat);
302 | //display.display();
303 | // End Battery Updates
304 | }
305 |
306 | // OLED Updates
307 | // ============
308 | void oled_Updates(){
309 | if (curMode== 0 ) {
310 | curMode = 0;
311 | display.setTextSize(1); // Normal 1:1 pixel scale
312 | display.setTextColor(SSD1306_WHITE, BLACK); // Draw white text
313 | display.setCursor(0,1); // Start at top-left corner
314 | display.println(F("Mode: Analog "));
315 | display.display();
316 | } else {
317 | curMode = 1;
318 | display.setTextSize(1); // Normal 1:1 pixel scale
319 | display.setTextColor(SSD1306_WHITE, BLACK); // Draw white text
320 | display.setCursor(0,1); // Start at top-left corner
321 | display.println(F("Mode: Digital "));
322 | display.display();
323 | }
324 | // End OLED Updates
325 | }
326 |
327 |
328 | // Controller related items
329 | // ========================
330 | void pollController(){
331 | //Check ESP Core Controller Polling Occurs on
332 | //Serial.print("Controller Polling Core ");
333 | //Serial.println(xPortGetCoreID());
334 |
335 | //Make sure that we sync timestamp and last timestamp on first run
336 | if (lastTimeStamp = 0){
337 | lastTimeStamp = timeStamp;
338 | //hacktest MPU initialization on first run
339 | //initializeSensor();
340 | }
341 |
342 | // Start The Data Read
343 | // Is the Controller ready to send the data?
344 | TLACK = digitalRead(TLPin);
345 |
346 | // Have we read all the bytes needed for each mode?
347 | if (byteCounter > modeCounter) {
348 | // Set Not ready for Data Coms
349 | digitalWrite(THPin, HIGH);
350 | digitalWrite(TRPin, HIGH);
351 |
352 | // Are we using Analogue Mode or Digital?
353 | if (modeCounter == AnalogMode) {
354 | curMode = 0;
355 | currentButtonStates[0] = 0;
356 | } else {
357 | curMode = 1;
358 | currentButtonStates[0] = 1;
359 | }
360 |
361 | // Decoded Controller Data Successfully
362 | // Proceed based on Analog or Digital Mode
363 | //
364 | // Note that BLEgamepad check occurs in combination with successfully decoded data
365 | // This avoids a bug in NIMBLE where blegamepad could under some circumstances attempt button send prior to connecting and cause abort
366 | if (DecodeData == 1 && bleGamepad.isConnected()) {
367 | //Analog
368 | if (modeCounter == AnalogMode) {
369 | //Analog Mode - Process Input
370 | //Begin all Analog Mode data processing
371 |
372 | //DPAD
373 | if (dataArrayBit6[1] != 0 && dataArrayBit7[1] != 0 && dataArrayBit5[1] != 0 && dataArrayBit4[1] != 0){
374 | bleGamepad.setHat1(DPAD_CENTERED);
375 | currentButtonStates[1] = 0;
376 | }
377 | if (dataArrayBit4[1] == 0 && (dataArrayBit7[1] != 0 && dataArrayBit6[1] != 0)) {
378 | //Serial.print(" U");
379 | bleGamepad.setHat1(DPAD_UP);
380 | currentButtonStates[1] = 1;
381 | }
382 | if (dataArrayBit5[1] == 0 && (dataArrayBit7[1] != 0 && dataArrayBit6[1] != 0)) {
383 | //Serial.print(" D");
384 | bleGamepad.setHat1(DPAD_DOWN);
385 | currentButtonStates[1] = 2;
386 | }
387 | if (dataArrayBit6[1] == 0 && (dataArrayBit4[1] != 0 && dataArrayBit5[1] != 0)) {
388 | //Serial.print(" L");
389 | bleGamepad.setHat1(DPAD_LEFT);
390 | currentButtonStates[1] = 3;
391 | }
392 | if (dataArrayBit7[1] == 0 && (dataArrayBit4[1] != 0 && dataArrayBit5[1] != 0)) {
393 | //Serial.print(" R");
394 | bleGamepad.setHat1(DPAD_RIGHT);
395 | currentButtonStates[1] = 4;
396 | }
397 | if (dataArrayBit4[1] == 0 && dataArrayBit6[1] == 0) {
398 | //Serial.print(" U/L");
399 | bleGamepad.setHat1(DPAD_UP_LEFT);
400 | currentButtonStates[1] = 5;
401 | }
402 | if (dataArrayBit4[1] == 0 && dataArrayBit7[1] == 0) {
403 | //Serial.print(" U/R");
404 | bleGamepad.setHat1(DPAD_UP_RIGHT);
405 | currentButtonStates[1] = 6;
406 | }
407 | if (dataArrayBit5[1] == 0 && dataArrayBit6[1] == 0) {
408 | //Serial.print(" D/L");
409 | bleGamepad.setHat1(DPAD_DOWN_LEFT);
410 | currentButtonStates[1] = 7;
411 | }
412 | if (dataArrayBit5[1] == 0 && dataArrayBit7[1] == 0) {
413 | //Serial.print(" D/R");
414 | bleGamepad.setHat1(DPAD_DOWN_RIGHT);
415 | currentButtonStates[1] = 8;
416 | }
417 | // End DPAD
418 |
419 | //Buttons
420 | if (dataArrayBit2[2] == 0) {
421 | Serial.print(" A");
422 | bleGamepad.press(BUTTON_4);
423 | currentButtonStates[3] = 1;
424 | } else {
425 | //Serial.print(" ");
426 | bleGamepad.release(BUTTON_4);
427 | currentButtonStates[3] = 0;
428 | }
429 | if (dataArrayBit0[2] == 0) {
430 | //Serial.print(" B");
431 | bleGamepad.press(BUTTON_1);
432 | currentButtonStates[4] = 1;
433 | } else {
434 | //Serial.print(" ");
435 | bleGamepad.release(BUTTON_1);
436 | currentButtonStates[4] = 0;
437 | }
438 | if (dataArrayBit1[2] == 0) {
439 | //Serial.print(" C");
440 | bleGamepad.press(BUTTON_2);
441 | currentButtonStates[5] = 1;
442 | } else {
443 | //Serial.print(" ");
444 | bleGamepad.release(BUTTON_2);
445 | currentButtonStates[5] = 0;
446 | }
447 | if (dataArrayBit6[2] == 0) {
448 | //Serial.print(" X");
449 | bleGamepad.press(BUTTON_7);
450 | currentButtonStates[6] = 1;
451 | } else {
452 | //Serial.print(" ");
453 | bleGamepad.release(BUTTON_7);
454 | currentButtonStates[6] = 0;
455 | }
456 | if (dataArrayBit5[2] == 0) {
457 | // Serial.print(" Y");
458 | bleGamepad.press(BUTTON_5);
459 | currentButtonStates[7] = 1;
460 | } else {
461 | //Serial.print(" ");
462 | bleGamepad.release(BUTTON_5);
463 | currentButtonStates[7] = 0;
464 | }
465 | if (dataArrayBit4[2] == 0) {
466 | //Serial.print(" Z");
467 | bleGamepad.press(BUTTON_8);
468 | currentButtonStates[8] = 1;
469 | } else {
470 | //Serial.print(" ");
471 | bleGamepad.release(BUTTON_8);
472 | currentButtonStates[8] = 0;
473 | }
474 | // Uncomment for L/R triggers to send digital in addition to analog values
475 | // May have wrong button_number defined here in the blegamepad.press setting
476 | //if (dataArrayBit3[3] == 0) {
477 | //Serial.print(" LT");
478 | // bleGamepad.press(BUTTON_5);
479 | // currentButtonStates[9] = 1;
480 | //} else {
481 | //Serial.print(" ");
482 | // bleGamepad.release(BUTTON_5);
483 | // currentButtonStates[9] = 0;
484 | //}
485 | //if (dataArrayBit7[2] == 0) {
486 | //Serial.print(" RT");
487 | // bleGamepad.press(BUTTON_6);
488 | // currentButtonStates[10] = 1;
489 | //} else {
490 | //Serial.print(" ");
491 | // bleGamepad.release(BUTTON_6);
492 | // currentButtonStates[10] = 1;
493 | //}
494 | if (dataArrayBit3[2] == 0) {
495 | //Serial.print(" Start ");
496 | bleGamepad.press(BUTTON_12);
497 | currentButtonStates[2] = 1;
498 | } else {
499 | bleGamepad.release(BUTTON_12);
500 | currentButtonStates[2] = 0;
501 | }
502 | // Latency Test Pin
503 | // Intended for BlueRetro latency button
504 | // Can be used for other additional buttons
505 | //
506 | // Note this sends "Start" but can be adjusted to press any other button
507 | if (digitalRead(latPin) == LOW) {
508 | //Serial.print("LAT");
509 | bleGamepad.press(BUTTON_3);
510 | currentButtonStates[3] = 1;
511 | } else {
512 | bleGamepad.release(BUTTON_3);
513 | currentButtonStates[3] = 0;
514 | }
515 |
516 | // Up / Down
517 | if (dataArrayBit7[4] == 1) {
518 | upDownValue = dataArrayBit0[5] + (dataArrayBit1[5]<<1) + (dataArrayBit2[5]<<2) + (dataArrayBit3[5]<<3) + (dataArrayBit4[4]<<4) + (dataArrayBit5[4]<<5) + (dataArrayBit6[4]<<6);
519 | //bleAnalogX = map(upDownValue, 0, 127, 1, 32767);
520 | bleAnalogX = map(upDownValue, 0, 127, 16384, 32767);
521 |
522 | } else {
523 | upDownValue = !dataArrayBit0[5] + (!dataArrayBit1[5]<<1) + (!dataArrayBit2[5]<<2) + (!dataArrayBit3[5]<<3) + (!dataArrayBit4[4]<<4) + (!dataArrayBit5[4]<<5) + (!dataArrayBit6[4]<<6);
524 | //bleAnalogX = map(upDownValue, 1, 127, -1, -32767);
525 | bleAnalogX = map(upDownValue, 0, 127, 16383, 1);
526 | }
527 | // Deadzone fix - X Axis
528 | // Value is checked based on map output
529 | //=======COMMENTED THIS OUT TEMPORARILY
530 | //if ((bleAnalogX < 0 && bleAnalogX > -500)||(bleAnalogX < 0 && bleAnalogX > -500)){
531 | // bleAnalogX = 0;
532 | // }
533 |
534 |
535 | //Analog Debugs
536 | //Serial.print(" bleAnalogX ");
537 | //Serial.println(bleAnalogX);
538 | // Format Value to 3 Chars long
539 | //char buf[] = "000";
540 | //sprintf(buf, "%03i", upDownValue);
541 |
542 | // Left / Right
543 | if (dataArrayBit7[3] == 1) {
544 | //Serial.print(" R = ");
545 | leftRightValue = dataArrayBit0[4] + (dataArrayBit1[4]<<1) + (dataArrayBit2[4]<<2) + (dataArrayBit3[4]<<3) + (dataArrayBit4[3]<<4) + (dataArrayBit5[3]<<5) + (dataArrayBit6[3]<<6);
546 | //bleAnalogY = map(leftRightValue, 1, 127, 1, 32767);
547 | bleAnalogY = map(leftRightValue, 0, 127, 16384, 32767);
548 | } else {
549 | leftRightValue = !dataArrayBit0[4] + (!dataArrayBit1[4]<<1) + (!dataArrayBit2[4]<<2) + (!dataArrayBit3[4]<<3) + (!dataArrayBit4[3]<<4) + (!dataArrayBit5[3]<<5) + (!dataArrayBit6[3]<<6);
550 |
551 | bleAnalogY = map(leftRightValue, 0, 127, 16383, 1);
552 | }
553 | //=======COMMENTED THIS OUT TEMPORARILY
554 | // Deadzone fix - Y Axis
555 | // Value is checked based on map output
556 | //if ((bleAnalogY > 0 && bleAnalogY < 500)||(bleAnalogY < 0 && bleAnalogY > -500)){
557 | // bleAnalogY = 0;
558 | //}
559 | // Set Analog Pad/Left Thumb Stick X Y Values in Blegamepad
560 | // This is an easy place to flip the X and Yresults if backwards for your use case
561 | bleGamepad.setX(bleAnalogY);
562 | bleGamepad.setY(bleAnalogX);
563 | // Track State of Analog Sticks X and Y Values
564 | currentButtonStates[11] = bleAnalogX;
565 | currentButtonStates[12] = bleAnalogY;
566 | //unused at this time
567 | //currentButtonStates[13] = 0;
568 | //currentButtonStates[14] = 0;
569 |
570 | // Decode Triggers
571 | char trbuf[] = "00";
572 | //Left Trigger
573 | ltValue = (dataArrayBit7[6] * 8) + (dataArrayBit6[6] * 4) + (dataArrayBit5[6] * 2) + (dataArrayBit4[6] * 1);
574 | //bleLTrigger = map(ltValue, 0, 15, -32767, 32767);
575 | bleLTrigger = map(ltValue, 0, 15, 1, 32767);
576 | bleGamepad.setLeftTrigger(bleLTrigger);
577 | //Track State of L trigger
578 | currentButtonStates[9] = bleLTrigger;
579 |
580 | //sprintf(trbuf, "%02i", ltValue);
581 | //Serial.print(" LT = ");
582 | //Serial.print(trbuf);
583 |
584 | //Right Trigger
585 | rtValue = (dataArrayBit7[5] * 8) + (dataArrayBit6[5] * 4) + (dataArrayBit5[5] * 2) + (dataArrayBit4[5] * 1);
586 | //bleRTrigger = map(rtValue, 0, 15, 32767, -32767);
587 | bleRTrigger = map(rtValue, 0, 15, 1, 32767);
588 | bleGamepad.setRightTrigger(bleRTrigger);
589 | //Track State of R trigger
590 | currentButtonStates[10] = bleRTrigger;
591 | //sprintf(trbuf, "%02i", rtValue);
592 | //Serial.print(" RT = ");
593 | //Serial.print(trbuf);
594 |
595 | //Debug
596 | unsigned int wMark1 = uxTaskGetStackHighWaterMark(nullptr);
597 | printf("Watermark before SendReportA loop is is %u\n", wMark1);
598 |
599 | //All Input states gathered Send Update if current and previous states do not match
600 | //bleGamepad.sendReport();
601 | if (currentButtonStates != previousButtonStates)
602 | {
603 | for (byte currentIndex = 0; currentIndex < numOfButtons; currentIndex++)
604 | {
605 | previousButtonStates[currentIndex] = currentButtonStates[currentIndex];
606 | }
607 |
608 | bleGamepad.sendReport();
609 | }
610 | //End all Analog Mode data
611 |
612 |
613 | } else {
614 | // Digital Mode - Process Input
615 | // ============================
616 |
617 | // DPAD
618 | if (dataArrayBit6[1] != 0 && dataArrayBit7[1] != 0 && dataArrayBit5[1] != 0 && dataArrayBit4[1] != 0){
619 | bleGamepad.setHat1(DPAD_CENTERED);
620 | currentButtonStates[1] = 0;
621 | }
622 | if (dataArrayBit4[0] == 0 && (dataArrayBit7[0] != 0 || dataArrayBit6[0] != 0)) {
623 | //Serial.print(" U ");
624 | bleGamepad.setHat1(DPAD_UP);
625 | currentButtonStates[1] = 1;
626 | }
627 | if (dataArrayBit5[0] == 0 && (dataArrayBit7[0] != 0 || dataArrayBit6[0] != 0)) {
628 | //Serial.print(" D ");
629 | bleGamepad.setHat1(DPAD_DOWN);
630 | currentButtonStates[1] = 2;
631 | }
632 | if (dataArrayBit6[0] == 0 && (dataArrayBit4[0] !=0 || dataArrayBit5[0] != 0)) {
633 | //Serial.print(" L ");
634 | bleGamepad.setHat1(DPAD_LEFT);
635 | currentButtonStates[1] = 3;
636 | }
637 | if (dataArrayBit7[0] == 0 && (dataArrayBit4[0] !=0 || dataArrayBit5[0] != 0)) {
638 | //Serial.print(" R ");
639 | bleGamepad.setHat1(DPAD_RIGHT);
640 | currentButtonStates[1] = 4;
641 | }
642 | if (dataArrayBit4[0] == 0 && dataArrayBit6[0] == 0) {
643 | //Serial.print(" U/L ");
644 | bleGamepad.setHat1(DPAD_UP_LEFT);
645 | currentButtonStates[1] = 5;
646 | }
647 | if (dataArrayBit4[0] == 0 && dataArrayBit7[0] == 0) {
648 | //Serial.print(" U/R ");
649 | bleGamepad.setHat1(DPAD_UP_RIGHT);
650 | currentButtonStates[1] = 6;
651 | }
652 | if (dataArrayBit5[0] == 0 && dataArrayBit6[0] == 0) {
653 | //Serial.print(" D/L ");
654 | bleGamepad.setHat1(DPAD_DOWN_LEFT);
655 | currentButtonStates[1] = 7;
656 | }
657 | if (dataArrayBit5[0] == 0 && dataArrayBit7[0] == 0) {
658 | //Serial.print(" D/R ");
659 | bleGamepad.setHat1(DPAD_DOWN_RIGHT);
660 | currentButtonStates[1] = 8;
661 | }
662 |
663 | //Buttons
664 | if (dataArrayBit2[1] == 0) {
665 | //Serial.print(" A ");
666 | bleGamepad.press(BUTTON_4);
667 | currentButtonStates[3] = 1;
668 | } else {
669 | bleGamepad.release(BUTTON_4);
670 | currentButtonStates[3] = 0;
671 | }
672 | if (dataArrayBit0[1] == 0) {
673 | //Serial.print(" B ");
674 | bleGamepad.press(BUTTON_1);
675 | currentButtonStates[4] = 1;
676 | } else {
677 | bleGamepad.release(BUTTON_1);
678 | currentButtonStates[4] = 0;
679 | }
680 | if (dataArrayBit1[1] == 0) {
681 | //Serial.print(" C ");
682 | bleGamepad.press(BUTTON_2);
683 | currentButtonStates[5] = 1;
684 | } else {
685 | bleGamepad.release(BUTTON_2);
686 | currentButtonStates[5] = 0;
687 | }
688 | if (dataArrayBit6[1] == 0) {
689 | //Serial.print(" X ");
690 | bleGamepad.press(BUTTON_7);
691 | currentButtonStates[6] = 1;
692 | } else {
693 | bleGamepad.release(BUTTON_7);
694 | currentButtonStates[6] = 0;
695 | }
696 | if (dataArrayBit5[1] == 0) {
697 | //Serial.print(" Y ");
698 | bleGamepad.press(BUTTON_5);
699 | currentButtonStates[7] = 1;
700 | } else {
701 | bleGamepad.release(BUTTON_5);
702 | currentButtonStates[7] = 0;
703 | }
704 | if (dataArrayBit4[1] == 0) {
705 | //Serial.print(" Z ");
706 | bleGamepad.press(BUTTON_8);
707 | currentButtonStates[8] = 1;
708 | } else {
709 | bleGamepad.release(BUTTON_8);
710 | currentButtonStates[8] = 0;
711 | }
712 | if (dataArrayBit3[2] == 0) {
713 | //Serial.print(" LT ");
714 | bleGamepad.press(BUTTON_11);
715 | currentButtonStates[9] = 1;
716 | } else {
717 | bleGamepad.release(BUTTON_11);
718 | currentButtonStates[9] = 0;
719 | }
720 | if (dataArrayBit7[1] == 0) {
721 | //Serial.print(" RT ");
722 | bleGamepad.press(BUTTON_13);
723 | currentButtonStates[10] = 1;
724 | } else {
725 | bleGamepad.release(BUTTON_13);
726 | currentButtonStates[10] = 0;
727 | }
728 | if (dataArrayBit3[1] == 0) {
729 | //Serial.println(" Start ");
730 | bleGamepad.press(BUTTON_12);
731 | currentButtonStates[2] = 1;
732 | } else {
733 | ////Serial.println(" ");
734 | bleGamepad.release(BUTTON_12);
735 | currentButtonStates[2] = 0;
736 | }
737 | // Latency Test Pin
738 | // Intended for BlueRetro latency test pad to measure BLEGamepad update speeds without modifying the Controller
739 | if (digitalRead(latPin) == LOW) {
740 | Serial.print("Latency Test Press");
741 | bleGamepad.press(BUTTON_3);
742 | currentButtonStates[2] = 1;
743 | } else {
744 | bleGamepad.release(BUTTON_3);
745 | currentButtonStates[2] = 0;
746 | }
747 |
748 | // unsigned int wMark2 = uxTaskGetStackHighWaterMark(nullptr);
749 | // printf("Watermark - SendReport B loop %u\n", wMark2);
750 |
751 | // All Input states gathered Send Update if state has changed
752 | if (currentButtonStates != previousButtonStates){
753 | for (byte currentIndex = 0; currentIndex < numOfButtons; currentIndex++)
754 | {
755 | previousButtonStates[currentIndex] = currentButtonStates[currentIndex];
756 | }
757 | bleGamepad.sendReport();
758 | }
759 | }
760 | // End Digital Mode - Process Input
761 | // ================================
762 |
763 |
764 | // Invalid Data or no connection error state
765 | // =========================================
766 | // Communication or wiring issue
767 | } else {
768 | for (int printByteCounter = 0; printByteCounter < modeCounter + 1; printByteCounter++) {
769 | int derpvar;
770 | derpvar=0;
771 | //Serial.println("Error: Gamepad may not be paired OR Pinout/Timing Incorrect");
772 | //Uncomment lines for additional debug output
773 | //Serial.print(" -- Byte ");
774 | //Serial.print(printByteCounter);
775 | //Serial.print(" - ");
776 | //Serial.print(dataArrayBit0[printByteCounter]);
777 | //Serial.print(dataArrayBit1[printByteCounter]);
778 | //Serial.print(dataArrayBit2[printByteCounter]);
779 | //Serial.print(dataArrayBit3[printByteCounter]);
780 | //Serial.print(dataArrayBit4[printByteCounter]);
781 | //Serial.print(dataArrayBit5[printByteCounter]);
782 | //Serial.print(dataArrayBit6[printByteCounter]);
783 | //Serial.print(dataArrayBit7[printByteCounter]);
784 | }
785 | // End Invalid Data
786 | //=================
787 | }
788 | // End Polling
789 | // ===========
790 |
791 | // Reset variables ready for data read.
792 | byteCounter = 0;
793 | nibble0Read = 0;
794 |
795 | // Setting Current Time for data read
796 | timeStamp = millis();
797 | }
798 |
799 |
800 | // Check to see if the Controller is ready to send data and if we have read any data yet
801 | if (TLACK == HIGH and nibble0Read == 0) {
802 | digitalWrite(THPin, LOW);
803 | delayMicroseconds(4); // I don't think I need this
804 | digitalWrite(TRPin, LOW);
805 | delayMicroseconds(4);
806 | //delayMicroseconds(1);
807 | }
808 |
809 |
810 | // If the 1st nibble is being sent and we havn't read the 1st nibble yet get the data from the pins
811 | if (TLACK == LOW and nibble0Read == 0) {
812 | // Sets ready to read the 1st nibble of data
813 | digitalWrite(TRPin, HIGH);
814 | delayMicroseconds(8); //For ESP32 with lower setting get random button press
815 |
816 | // Read the Data for the 1st Nibble
817 | dataArrayBit0[byteCounter] = digitalRead(dataPinD0);
818 | dataArrayBit1[byteCounter] = digitalRead(dataPinD1);
819 | dataArrayBit2[byteCounter] = digitalRead(dataPinD2);
820 | dataArrayBit3[byteCounter] = digitalRead(dataPinD3);
821 |
822 | if (dataArrayBit0[byteCounter] > 1) {
823 | dataArrayBit0[byteCounter] = 0;
824 | }
825 | if (dataArrayBit1[byteCounter] > 1) {
826 | dataArrayBit1[byteCounter] = 0;
827 | }
828 | if (dataArrayBit2[byteCounter] > 1) {
829 | dataArrayBit2[byteCounter] = 0;
830 | }
831 | if (dataArrayBit3[byteCounter] > 1) {
832 | dataArrayBit3[byteCounter] = 0;
833 | }
834 |
835 | // 1st Nibble has been read
836 | nibble0Read = 1;
837 |
838 | // Check if we are reading data for Analogue mode or Digital Mode
839 | // The mode defines the number of Bytes we need to read
840 | if (byteCounter == 0) {
841 | if ((dataArrayBit0[0] == 1 and dataArrayBit1[0] == 0 and dataArrayBit2[0] == 0 and dataArrayBit3[0] == 0) or (dataArrayBit0[0] == 0 and dataArrayBit1[0] == 1 and dataArrayBit2[0] == 1 and dataArrayBit3[0] == 0) or (dataArrayBit0[0] == 1 and dataArrayBit1[0] == 1 and dataArrayBit2[0] == 1 and dataArrayBit3[0] == 0) ) {
842 | modeCounter = AnalogMode;
843 | } else {
844 | modeCounter = DigitalMode;
845 | }
846 | }
847 | }
848 |
849 | // Check if the 2nd Nibble is being sent and if we have already read the 1st Nibble
850 | if (TLACK == HIGH and nibble0Read == 1) {
851 | // Sets ready to read the 2nd Nibble
852 | digitalWrite(TRPin, LOW);
853 | delayMicroseconds(8);
854 | // Read the data for the 2nd Nibble
855 | dataArrayBit4[byteCounter] = digitalRead(dataPinD0);
856 | dataArrayBit5[byteCounter] = digitalRead(dataPinD1);
857 | dataArrayBit6[byteCounter] = digitalRead(dataPinD2);
858 | dataArrayBit7[byteCounter] = digitalRead(dataPinD3);
859 | if (dataArrayBit4[byteCounter] > 1) {
860 | dataArrayBit4[byteCounter] = 0;
861 | }
862 | if (dataArrayBit5[byteCounter] > 1) {
863 | dataArrayBit5[byteCounter] = 0;
864 | }
865 | if (dataArrayBit6[byteCounter] > 1) {
866 | dataArrayBit6[byteCounter] = 0;
867 | }
868 | if (dataArrayBit7[byteCounter] > 1) {
869 | dataArrayBit7[byteCounter] = 0;
870 | }
871 |
872 | // Reset the 1st Nibble read variable, ready for the next Byte of data
873 | nibble0Read = 0;
874 |
875 | // Increase the Byte counter by 1 so we are ready to read the next Byte of data
876 | byteCounter++;
877 | }
878 |
879 | // Time Stamp Routines to check if data has paused.
880 | currentMillis = millis();
881 |
882 | if (currentMillis - timeStamp >= interval) {
883 | // Resetting All Variables
884 | timeStamp = millis();
885 | digitalWrite(THPin, HIGH);
886 | digitalWrite(TRPin, HIGH);
887 | byteCounter = 0;
888 | nibble0Read = 0;
889 | Serial.println("Resetting");
890 | }
891 | }
892 | //=============================
893 | // End Controller related items
894 |
895 | // Pin anything that isn't the controller or bluetooth to core 0
896 | //==============================================================
897 |
898 | void Task1code( void * pvParameters ){
899 | //Serial.print("OLED Update ESP Core ");
900 | //Serial.println(xPortGetCoreID());
901 |
902 | for(;;){
903 | //Serial.print("timeStamp val" );
904 | if (timeStamp == 0){
905 | //bootLogo();
906 | timeStamp = 1;
907 | }
908 | //oled_Updates();
909 | //getBatStat();
910 | Serial.print(" ");
911 | }
912 | }
913 | // End Core Pinning
914 | //=================
915 |
916 |
917 | // Controller and Bluetooth Jobs here
918 | void Task2code( void * pvParameters ){
919 | //Serial.print("Task2code running on core ");
920 | //Serial.println(xPortGetCoreID());
921 |
922 | for(;;){
923 | //debug
924 | // unsigned int wMark3 = uxTaskGetStackHighWaterMark(nullptr);
925 | // printf("Watermark before FOR Loop is %u\n", wMark3);
926 |
927 | pollController();
928 | //debug
929 | // unsigned int wMark = uxTaskGetStackHighWaterMark(nullptr);
930 | // printf("Watermark after FOR Loop is %u\n", wMark);
931 | }
932 | }
933 |
934 |
935 | // This is the main loop due to threading in arduino + core tasking in RTOS
936 | //==========================================================================
937 | void setup() {
938 | // Check ESP Core
939 | //Serial.print("Setup Core");
940 | //Serial.println(xPortGetCoreID());
941 |
942 |
943 | // Start BLE Gamepad
944 | BleGamepadConfiguration bleGamepadConfig;
945 | bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD); // CONTROLLER_TYPE_JOYSTICK, CONTROLLER_TYPE_GAMEPAD (DEFAULT), CONTROLLER_TYPE_MULTI_AXIS
946 | bleGamepadConfig.setButtonCount(numOfButtons);
947 | bleGamepadConfig.setWhichAxes(enableX, enableY, enableZ, enableRX, enableRY, enableRZ, enableSlider1, enableSlider2); // Can also be done per-axis individually. All are true by default
948 | bleGamepadConfig.setHatSwitchCount(numOfHatSwitches); // 1 by default
949 | bleGamepadConfig.setAxesMin(0x8001); // -32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
950 | //
951 | //bleGamepadConfig.setAxesMin(0x0001); // -32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
952 | bleGamepadConfig.setAxesMax(0x7FFF); // 32767 --> int16_t - 16 bit signed integer - Can be in decimal or hexadecimal
953 | // Other Available Special Button Options
954 | // bleGamepadConfig.setIncludeStart(true);
955 | // bleGamepadConfig.setIncludeSelect(true);
956 | // bleGamepadConfig.setIncludeMenu(true);
957 | // bleGamepadConfig.setIncludeHome(true);
958 | // bleGamepadConfig.setIncludeBack(true);
959 | // bleGamepadConfig.setIncludeVolumeInc(true);
960 | // bleGamepadConfig.setIncludeVolumeDec(true);
961 | // bleGamepadConfig.setIncludeVolumeMute(true);
962 | // Use or disable BLEGampead AutoReporting
963 | // AutoReport can impact latency negatively with high speed of updates
964 | bleGamepadConfig.setAutoReport(false); // This is true by default
965 | bleGamepad.begin(&bleGamepadConfig);
966 |
967 |
968 | // Setting input and output pins for Comms with Controller
969 | // Use Heavy and Lightwing pinout settings instead of changing this
970 | //==========================// Pin 1 = +5V
971 | pinMode(dataPinD1, INPUT); // Pin 2 = Data D1
972 | pinMode(dataPinD0, INPUT); // Pin 3 = Data D0
973 | pinMode(THPin, OUTPUT); // Pin 4 = TH Select
974 | pinMode(TRPin, OUTPUT); // Pin 5 = TR Request
975 | pinMode(TLPin, INPUT); // Pin 6 = TL Response
976 | pinMode(dataPinD3, INPUT); // Pin 7 = Data D3
977 | pinMode(dataPinD2, INPUT); // Pin 8 = Data D2
978 | //==========================// Pin 9 = GND
979 |
980 | // Set pin state to begin reading controller state
981 | digitalWrite(THPin, HIGH);
982 | digitalWrite(TRPin, HIGH);
983 |
984 | // Define Latency test pin
985 | pinMode(latPin,INPUT_PULLUP );
986 |
987 |
988 | // Setup Serial comms for Serial Monitor
989 | Serial.begin(115200);
990 | Serial.print("Device Booting....");
991 |
992 | // Creates Tasks for Core 0
993 | xTaskCreatePinnedToCore(
994 | Task1code, /* Task function. */
995 | "Task1", /* name of task. */
996 | 5000, /* Stack size of task */ //originally 10k
997 | NULL, /* parameter of the task */
998 | 3, /* priority of the task */
999 | &Task1, /* Task handle to keep track of created task */
1000 | 0); /* pin task to core 0 */
1001 |
1002 | //Creates Tasks for Core 0
1003 | xTaskCreatePinnedToCore(
1004 | Task2code, /* Task function. */
1005 | "Task2", /* name of task. */
1006 | 5000, /* Stack size of task */
1007 | NULL, /* parameter of the task */
1008 | 2, /* priority of the task */
1009 | &Task2, /* Task handle to keep track of created task */
1010 | 1); /* pin task to core 1 */
1011 |
1012 | }
1013 |
1014 |
1015 | // Loop will always run on Core 1
1016 | void loop(){
1017 | // Putting stuff here will break some automatic aspects of RTOS task cleanup
1018 | // All tasks/jobs should be performed from setup loop
1019 | }
1020 |
1021 | //Currently unused setup for Motion Controls
1022 | // All this code is trashed and intermixed (sorry) but the idea is
1023 | // initializeSensor -> setupMPU -> GetTiltMpu
1024 | void initializeSensor(){
1025 | // Perfrom full reset as per MPU-6000/MPU-6050 Register Map and Descriptions, Section 4.28, pages 40 to 41.
1026 | // performing full device reset, disables temperature sensor, disables SLEEP mode
1027 | Wire.beginTransmission(0x68); // Device address.
1028 | Wire.write(0x6B); // PWR_MGMT_1 register.
1029 | Wire.write(0b10001000); // DEVICE_RESET, TEMP_DIS.
1030 | Wire.endTransmission();
1031 | delay(100); // Wait for reset to complete.
1032 |
1033 | Wire.beginTransmission(0x68); // Device address.
1034 | Wire.write(0x68); // SIGNAL_PATH_RESET register.
1035 | Wire.write(0b00000111); // GYRO_RESET, ACCEL_RESET, TEMP_RESET.
1036 | Wire.endTransmission();
1037 | delay(100); // Wait for reset to complete.
1038 |
1039 | // Disable SLEEP mode because the reset re-enables it. Section 3, PWR_MGMT_1 register, page 8.
1040 | Wire.beginTransmission(MPU_addr); // Device address.
1041 | Wire.write(0x6B); // PWR_MGMT_1 register.
1042 | Wire.write(0b00001000); // SLEEP = 0, TEMP_DIS = 1.
1043 | Wire.endTransmission();
1044 | }
1045 | // =============
1046 | // End Start MPU
1047 |
1048 | void setupMPU() {
1049 | //Setup Accelerometer
1050 | //Wire.begin();
1051 |
1052 | //Configure MPU Connectivity
1053 | //Wire.beginTransmission(MPU_addr);
1054 | //Wire.write(0x68);
1055 | //Wire.write(0x00); // Make reset - place a 0 into the 6B register
1056 | //Wire.endTransmission(true);
1057 | //Wire.write(0);
1058 | //Wire.endTransmission(true);
1059 |
1060 |
1061 | //Adafruit_MPU6050 mpu;
1062 | //if (!Wire.begin()) {
1063 | // Serial.println("Failed to find MPU6050 chip");
1064 | // while (1) {
1065 | // delay(10);
1066 | // }
1067 | //}
1068 | //Serial.println("MPU6050 Found!");
1069 | //Setup Accelerometer End
1070 | }
1071 |
1072 |
1073 |
1074 | void getTiltMPU() {
1075 | //sensors_event_t a, g, temp;
1076 | //mpu.getEvent(&a, &g, &temp);
1077 | //Wire.begin();
1078 |
1079 | //Configure MPU Connectivity
1080 | //Wire.beginTransmission(MPU_addr);
1081 | //Wire.write(0x68);
1082 | //Wire.write(0);
1083 | //Wire.endTransmission(true);
1084 |
1085 | //Serial.begin(115200);
1086 | //void loop(){
1087 |
1088 | //Get Data from MPU
1089 | //Wire.beginTransmission(MPU_addr);
1090 | //Wire.write(0x3B);
1091 | //Wire.endTransmission(false);
1092 | //Wire.requestFrom(MPU_addr,14,true);
1093 |
1094 | //Store MPU Values
1095 | //AcX=Wire.read()<<8|Wire.read();
1096 | //AcY=Wire.read()<<8|Wire.read();
1097 | //AcZ=Wire.read()<<8|Wire.read();
1098 |
1099 | Serial.print("MPU X Y Z");
1100 | //Serial.print(a.acceleration.x, 1);
1101 | //Serial.print(a.acceleration.y, 1);
1102 | //Serial.print(a.acceleration.z, 1);
1103 | Serial.print("MPU GYRO");
1104 | //Serial.print(g.gyro.x, 1);
1105 | //Serial.print(g.gyro.y, 1);
1106 | //Serial.print(g.gyro.z, 1);
1107 |
1108 | //Convert stored values from Rads to Degrees
1109 | //int xAng = map(AcX,minVal,maxVal,-90,90);
1110 | //int yAng = map(AcY,minVal,maxVal,-90,90);
1111 | //int zAng = map(AcZ,minVal,maxVal,-90,90);
1112 | //x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);
1113 | //y= RAD_TO_DEG * (atan2(-xAng, -zAng)+PI);
1114 | //z= RAD_TO_DEG * (atan2(-yAng, -xAng)+PI);
1115 |
1116 | //Print current angles
1117 | //Serial.print("AngleX ");
1118 | //Serial.println(x);
1119 | //Serial.print("AngleY ");
1120 | //Serial.println(y);
1121 | //display.clearDisplay();
1122 | //display.setTextSize(1); // Normal 1:1 pixel scale
1123 | //display.setTextColor(SSD1306_WHITE, BLACK); // Draw white text
1124 | //display.setCursor(0,10);
1125 | //display.println("Tilt: On");
1126 | //display.setCursor(0,20); // r
1127 | //String derp1 = " X Axis: " + String(x);
1128 | //String derp2 = " Y Axis: " + String(y);
1129 | //display.clearDisplay();
1130 | //display.println(derp1);
1131 | //display.println(F("X Axis " + String(x)));
1132 | //display.setCursor(0,30);
1133 | //display.println(derp2);
1134 | //display.println(F("y Axis " + String(y)));
1135 | //display.display();
1136 | //
1137 |
1138 | //Limit Degrees of angle based on comfort prior to converting to BLEGamepad Vals
1139 | //Limit X
1140 | if (x < 160){
1141 | x=160;
1142 | }
1143 | if (x > 200){
1144 | x=200;
1145 | }
1146 | //Limit Y
1147 | if (y < 160){
1148 | y=160;
1149 | }
1150 | if (y > 200){
1151 | y=200;
1152 | }
1153 |
1154 | //Define DeadZones
1155 | //Will require calibration based on your install
1156 | //
1157 | //Create X deadzone
1158 | if ((x >= 170) && (x <= 190)){
1159 | x=180;
1160 | }
1161 | //
1162 | //Create Y deadzone
1163 | if ((y >= 170) && (y <= 190)){
1164 | y=180;
1165 | }
1166 |
1167 | //Map Values to Gamepad Ranges
1168 | xmap = map (x, 160, 200, 0, 32767);
1169 | ymap = map (y, 160, 200, 0, 32767);
1170 | //Print Mapped values
1171 | //Serial.print("Xmap BleG: ");
1172 | //Serial.println(xmap);
1173 | //Serial.print("Ymap BleG: ");
1174 | //Serial.println(ymap);
1175 |
1176 | Serial.println("-----------------------------------------");
1177 |
1178 | }
1179 |
--------------------------------------------------------------------------------