Dev Journal #37
Replies: 12 comments
-
Figured the LED fade, got confused because the example from ESP-IDF didn't use define for minimum duty cycle. Fade period will be 500ms. Already updated the LED module to use LEDC driver rather than GPIO for the error LED. Glad I resisted the urge to write my own LEDC driver 😂 |
Beta Was this translation helpful? Give feedback.
-
Got quite busy with my house moving lately. Everything in storage for 2 month and a half before moving in new house! Anyway I got the LED pulsing working and validated it's thread didn't interfere with anything. Now I'm going add a module to handle the BOOT switch event. I'm not using the GPIO int as it is dedicated to the Core1. So a thread poll the switch and once pressed it will periodically check (10 ms?) if the switch is released. Base on the time its hold and the current state it will call the proper callback to perform an action. The callback will be registered through a public function with info like function ptr, time to hold and some way to create dependency between them. |
Beta Was this translation helpful? Give feedback.
-
Got the boot switch working with the new design, holding it 3 sec start inquiry scan (and LED start to glow), short press while inquiry scan is on cancel it (and LED stop glowing), one short press outside of inquiry scan kick out all controllers as before. I also added a new attribute to the BLE webcfg interface to report the config version. The BLE cfg code is so obscure to me now, did it a year and half ago. Turnout it was quite robust haven't had the need to look much at it again since them! Just need to add the new inquiry option in the actual config now, add some upgrade code and then update the javascript 🤮 |
Beta Was this translation helpful? Give feedback.
-
Started working on the OTA firmware page. Got myself familiar with the JavaScript file reader API. Got a basic page that upload a file to the ESP32 via web Bluetooth. It quite slow as I split the file into 512 bytes chuck but I think I can improve it by using 4K chuck. |
Beta Was this translation helpful? Give feedback.
-
Starting to understand the BLE code again, lol. So turn out I used 512 bytes chuck because the WebBLE API limit the writeValue method for characteristic to that size. So no improvement possible going bigger. In any case 512 is not optimal because the effective maximum data payload for BLE packet (if MTU is maximum) is 244 bytes. So maximum throughput should be achieved by using 244 bytes chuck or maybe using double (488 bytes). I also noticed that when using Prepare write req/rsp my rsp always sent the whole payload back! I change it to only sent one dummy byte and it work fine. So that would probably reduce by half update time. Found a buffer overrun in that code too which luckily didn't had any effect since the buffer is quite big and the maximum config do not use all of it. |
Beta Was this translation helpful? Give feedback.
-
Turnout sending the whole packet back when using Prepare write req/rsp is the actual purpose and allow the controlling end (Web app in this case) to validate data was received properly. writeValue method will fail if not sent the original payload back. I settled on using 244 bytes payload as this is the maximum possible with the ESP32 (BLE max is 512 bytes) and this use a regular write request packet. Using chrome on a laptop the FW update take around 5 minutes using this maximum MTU. With Android it's super slow and take 45 minutes since for obscure reason Android keep the MTU to the minimum 23 bytes which trigger the use of Prepare write req/rsp which slow thing down even more than the small MTU. I could have used UDP style write packet but I feel having the handshake is safer for doing OTA updates. |
Beta Was this translation helpful? Give feedback.
-
Started looking at BLE controller support this weekend. The big thing there is the need to add Security Manager support. This take care of the paring process for LE devices. For a simple beacon like BlueRetro config interface this is not needed but for HID device this look to be a must. Read multiple time Part H in the Vol 3 of the Core 5.2 Bluetooth spec while cross checking a few BLE HID traces (Xbox series X/S, steam controller, BLE mouse, BLE KB). A lot of crypto algo stuff now take place at the host level unlike Bluetooth Classic. For a HID device I think all I need to implement is legacy BLE security "just work" method. With that method crypto needs are minimal and the important function are provided as part of the HCI (encrypt & rand). |
Beta Was this translation helpful? Give feedback.
-
I got the basic HCI LE cmd required to setup a bonded LE connection implemented. I also got a beginning of a security manager. I had initially with me only the Xbox Series X|S BLE controller and had issue receiving a pairing response from it. I would get it once out of 5 or 6 attempts. I though it might be a timing issue and so I tried to add some useless cmd between the LE connection and the pairing request. When doing using LE remote feature req or remote version request I get an error from the ESP bluetooth controller lib: lld_pdu_get_tx_flush_nb HCI packet count mismatch (0, 1) At that point I decided to update to the latest ESP-IDF as I saw a few fixes in the BT controller lib over the last 6 month. That didn't help. Then I checked in the Xbox accessories windows app if any update was available for the X|S controller and indeed one was available. So I updated the controller to FW 5.7.2688.0. that didn't help either. I then decided to go dig in my storage unit for a few others BLE device. Both the Steam controller and Logitech mouse pairing work 100% of the time. So yet another Xbox specific interop issue with the ESP32 like I had a year ago with the Xbox One S / adaptive controller. (that got fixed by a ESP-IDF update). I'll continue doing the BLE implementation with the Steam ctrl and the mouse. Once done I'll probably open a bug to espressif. |
Beta Was this translation helpful? Give feedback.
-
Made good progress on the BLE device support. I now got a working Security Manager module. I took the crypto function from Zephyr RTOS and adapted them for my need. Since my BT host run within the context of the BT controller task I can't block waiting for the controller rand & encrypt function as Zephyr do (It would deadlock). So I'm using a queue to save the request context and callback, And when I receive a rand or encrypt response, I fetch from the queue and execute the callback. Work well! A few keys gets exchange normally in the BLE pairing process. LTK is the important one (and is associated to a RAND and EDIV). ID key is related to the random BDADDR feature. There is also the sign key but not sure what it's for. In the case of HID device all we need is the device LTK so we can make it super simple by requesting only that one key in the pairing request and distribution no keys at all ourselves. The way reconnect work in BLE is a bit different than classic BT. In classic BT new pairing is done via inquiry scan and reconnection is done via page scan (This also affect who take the lead in establishing the HID connection). In BLE it's simply one type of scan for both and the whole process is pretty much the same. A device trying to establish a new pairing will send "connectable undirected" advertising report which may contain some info like device class, name or appearance. A device trying to reconnect will send a "connectable directed" advertising report than contain no info beside it's BDADDR since the host presumably already know the device. I this case the pairing process can be skip and the LTK exchanged in the original pairing is used to start encryption. It's important to respect the keys distribution agreed to in the pairing response, sending an additional unrequested key will make the device disconnect! As it is now I can pair my BLE mouse and my steam controller, and they both reconnect back! Now I need to do the ATT attribute discovery for HID report and then enable notification for the interesting ones. Once this is done I should be able to just send the HID payload to my existing HID module without any modification to it. |
Beta Was this translation helpful? Give feedback.
-
Lot of progress on the BLE side, it's pretty much done, just need to do more testing and some code cleanup. While the ATT attribute discovery isn't hard by itself to understand, it took me a while to settle on a flow that worked well. I didn't want to follow a systematic flow where the host go through every single attribute like pretty much every BLE stack do. All BlueRetro care about are the HID attributes and maybe the device name. So my first idea was to use "Read By Type Request" to get a list of the various HID attribute type UUIDs I wanted. This worked well with the Steam controller but the Logitech BLE mouse didn't like that, reporting that no attribute was found. Turn out BLE device are not required to implement all ATT commands! Interesting command like "Read Multiple Request" which allow to read multiple attribute at once are universally not supported by BLE devices. So in the end I had to settle to a more traditional approach. I found the HID attributes range via multiple "Read by Group Type Request" across the whole attribute database. Then I do multiple "Find Information Request" across the whole HID range to find the HID reports and other supporting attribute handles. After I read the Report Map attribute which the HID descriptor following the USB/HID standard definition. I parse the report using my existing module (no change!) and get a list of the interesting ones for BlueRetro. This only give us the report ID number however which is of no use with BLE, we then need for each BLE HID reports attribute found read it's associated HID reference attribute. This will tell us the HID report ID and also the report type (input, output or feature). Unlike USB and classic BT each report type for the same report ID get it's own unique handle. With this info we can now figure which handle address the HID reports we want and we can proceed with enabling notification by writing to the associated characteristic config handle. At that point I had both the Steam Controller and my Logitech mouse working 100%. However the Xbox X|S didn't work at all! It would take forever for the ESP32 to even see an advertising report from it. Once it didn't it would always fail at the paring step following connection and then disconnect. A few connection parameters need to be set for setting up scan and connection. Like connection interval min & max, connection latency & timeout. Initially I simply used the value I saw from one of by Ubuntu 18.04 trace of the steam controller. While troubleshooting I remembered the Xbox X|S controller didn't connect at with my Ubuntu laptop either. So I switched the parameter for those I saw in a Windows 10 trace I made with the Xbox X|S controller and it connected quite quickly this time and failed later at the HID reference read stage! Quite an improvement! It's possible to query the device for it's favorite connection parameter and using exactly those made the connection even faster. The Steam controller and mouse still worked perfectly with those new parameter as well. The last issue for the Xbox controller was that somehow it's report a few HID attribute in the "Find Information Response" as 128bits UUID rather than the short 16bits UUID ones, which I didn't anticipated. Further more those 128bits UUID are technically invalid, expanding a 16bits UUID is done by using a predefined 128bits UUID and replacing bytes at offset 12 & 13 with the 16bits UUID. Their base UUID is all 0s and only the 16bits portion is set properly! Anyway I made my code so it only extract the 16bits portion and ignore the rest. The Xbox series X|S now work perfectly!! The Steam controller support is via the Generic HID keyboard & Mouse mode of the controller. I will need to do some RE work to figure how to configure it as a proper gamepad. That will come later. I'll probably release this as a beta first since I don't have all my console available for testing properly at this time. |
Beta Was this translation helpful? Give feedback.
-
Last few months were quite busy. Moved to new house 2 month ago. Things mostly back to normal now. With my retro setup reinstalled, I was finally able to fully retest the adapter with all consoles and all possible accessory config earlier this month. Nothing new come up and so after fixing one reported issue I finally released v1.0 which mainly added BLE support but also contained some code rework/cleanup. With the incoming release of BT N64 controller for the Switch, I decided to prioritize a few tasks I've been pushing for a year. First I'm moving the Switch controller support to use the native protocol rather than the generic HID one. This will allow using the embedded calibration information from the controller. The SW ctrl got both a factory calibration and an optional user generated one. Those contain neutral position of each axes and also a relative absolute maximum from that neutral position in either direction. In addition the factory section also contain the deadzone radius at the center. This pretty much plug-in AS-IS in the way BlueRetro do thing, except that instead of using a fair value for all controllers now for the Switch it's precisely the right one for each controller axes. I also got the NES & SNES ones already and awaiting the FC, SFC & MD 6 btns from japan. Also was able to get an order in for the Genesis 3 btns. N64 was already sold out by the time I got the news, hopefully I can get one... I will add mapping quirks for all of them so they all endup with a good default. I'm also planning of finally adding the N64 memory pak support. In the end the BT N64 switch controller with BlueRetro should be pretty awesome :) |
Beta Was this translation helpful? Give feedback.
-
Lot have happened since the last entry to this dev journal! My wife and I had our first child. We are lucky to have a baby with perfect health (touching wood) but it still change your life :) . While on paternity leave I somehow managed to add support for the N64 controller pak. Not only one but four of them! 4 * 32KB simultaneously. The main reason to go with four right away was that Dreamcast VMU are 128KB anyway. So I wanted that part of the problem already taken care of for the future. (And yes due to lack of RAM, likely only one VMU will be supported for DC when I add support sometimes in the future). Since rumble pak was already supported, the N64 side of things was quite trivial to add. In fact it was pretty much already present. If you dig into the GitHub source from summer 2019 you could find that for a while it was supported. But then the project got some major rework and the higher level part got missing until now. What I called the higher level part is what takes the data written into the RAM buffer and write it into the flash memory. This sound simple but it was quite challenging. TBH BlueRetro as grown to be a quite bloated project over the last 2.5 years. I like everything to be statically allocated to avoid bad surprise at run time and since I support system detection & config at run time their is always a lot of unused statically allocated memory. The original ESP32 memory is quite fragmented physically to begin with and so with everything mentioned above their was no contiguous chuck of 128Kb available, neither 32KB. So the memory card module is one of the few to dynamically allocated it's memory. At first I tried to use blocks of 16KB as I had enough contiguous memory to get 8 block of 16KB. The way I designed the write back to flash is that when a write command comes from the N64 the data is written into the memory buffer. When write commands stop for 1 second then the system will write the modified block to a file on flash. While testing I noticed that fwrite function would quite often fail to write everything. So I added code to makes retries. But when retries occurred this had the effect of starving the Bluetooth controller task too much and connection with BT device sometimes got lost. Let's not forget that writing to flash stall the ESP32 CPUs as instruction code is read from the same flash. So I rewrote the flash write back to use 4KB block and write only one block every 1 second. So if more than one block got modified they will be wrote at an 1 sec interval and if fwrite failure occur the retries will be spaced at 1 sec interval as well. Using 4K block made the fwrite calls fail almost inexistent. Everything looked to work fines at that point until I started making RAM dump compare between data written and data restored at BlueRetro boot. A specific part of the memory was always getting corrupted after rebooting the adapter! I validated the data on flash was indeed ok. When formatting the region at run time and using it no corruption ever occurred either. This only happened once right after the memory got restored from flash. Something was going to write in a region it didn't own!! Ultimately I still don't know what goes writing there, I wish I had the time to figured this out but It was much simpler in the end to simply black list this chunk of memory:
This resolved my corruption at reboot issue. I think somehow It might be related to the ESP32 second core running bare metal hack BlueRetro uses. My focus for January and February was mostly me having fun building consolized Virtual Boy and GBA with BlueRetro integrated. The next big thing for BlueRetro is going to be official support for internal install, including wired controller detection (and the BT device port assignment base on it). Relay control to power on and off console on BT connect and via buttons macros. Reset switch buttons macro as well. Interesting stuff to do ahead :) |
Beta Was this translation helpful? Give feedback.
-
Lets try something new, I usually keep RE notes in my notebook but I'm in the process of moving to a new house so it's in storage for at least 3 month! (Like almost all my video games stuff) So maybe I can use GitHub discussion for that?
2021-06-08
Last night I started playing a bit with the ESP32's LED controller testing how the fading was working. While I understand what the duty cycle setting is, it's still not clear to me how its affect the ledc_set_fade_time_and_start function. Is the significant value range extremely restricted? This is part of my plan to improve BT inquiry mode. Demonic098 had some issue the way it currently work automatically. While inquiry is on the LED will now pulse as an indication. I will add a config option in the global section of web config to select between auto & manual. In auto the behavior will stay the same (inquiry on if no controller and 1min on after controller paired) Manual mode will disable that. Both mode will now have the possibility to enable inquiry mode by holding the BOOT buttons for 3 sec (quick press will still kick out all controllers).
This sound simple but it involve a lot of change in the config code (both FW & Web). I had the wisdom to add a magic number at the start of the config so we got at least a way to detect the original version with that. I will add a new BLE attribute to report the config version to the web page. If it doesn't exist then we got an old config. I will add a function to upgrade current config gracefully to latest version. But on downgrade I can't do much (the old firmware don't know about the new stuff) so it's just going to reset the config due to magic mismatch. So the web config will support any version.
Beta Was this translation helpful? Give feedback.
All reactions