1
0
mirror of https://github.com/whowechina/iidx_pico.git synced 2024-11-13 18:00:51 +01:00

Fix string issue in USB desc

This commit is contained in:
whowechina 2024-04-30 09:06:56 +08:00
parent 1d7b76654e
commit 671bb98cb2
4 changed files with 438 additions and 441 deletions

Binary file not shown.

386
README.md
View File

@ -1,193 +1,193 @@
# Pico IIDX - Beatmania IIDX controller # IIDX Pico - Beatmania IIDX controller
<img src="doc/main.jpg" width="80%"> <img src="doc/main.jpg" width="80%">
<img src="doc/stacked.jpg" width="80%"> <img src="doc/stacked.jpg" width="80%">
<video src="https://user-images.githubusercontent.com/11623830/229287886-d01893c5-04b6-41fc-a178-72c815e28c96.mp4" controls="controls" width="50%"></video> <video src="https://user-images.githubusercontent.com/11623830/229287886-d01893c5-04b6-41fc-a178-72c815e28c96.mp4" controls="controls" width="50%"></video>
Features: Features:
* It's thin, really thin. * It's thin, really thin.
* Detachable turntable using magnetic connector (soft hinge is another option). * Detachable turntable using magnetic connector (soft hinge is another option).
* HID lights, of course! * HID lights, of course!
* Key color theme and customization. * Key color theme and customization.
* Multiple turntable effects. * Multiple turntable effects.
* Many live settings. * Many live settings.
* Konami device mode for IIDX Ultimate Mobile. * Konami device mode for IIDX Ultimate Mobile.
* All source files open. * All source files open.
Thanks to many respectful guys/companies who made their tools or materials free or open source (KiCad, OpenSCAD, InkScape, Raspberry things). Thanks to many respectful guys/companies who made their tools or materials free or open source (KiCad, OpenSCAD, InkScape, Raspberry things).
## Notes ## Notes
This is a difficult build, it heavily depends on 3D printing, both FDM and SLA (resin). It also requires skills to solder tiny components and thin cables., much more difficult than my other projects such as Pico Popn. This is a difficult build, it heavily depends on 3D printing, both FDM and SLA (resin). It also requires skills to solder tiny components and thin cables., much more difficult than my other projects such as Pico Popn.
Move forward only if you're REALLY interested. Move forward only if you're REALLY interested.
Also, you can check out my other cool projects. Also, you can check out my other cool projects.
* Popn Pico: https://github.com/whowechina/popn_pico * Popn Pico: https://github.com/whowechina/popn_pico
<img src="https://raw.githubusercontent.com/whowechina/popn_pico/main/doc/main.jpg" width="180px"> <img src="https://raw.githubusercontent.com/whowechina/popn_pico/main/doc/main.jpg" width="180px">
* IIDX Teeny: https://github.com/whowechina/iidx_teeny * IIDX Teeny: https://github.com/whowechina/iidx_teeny
<img src="https://raw.githubusercontent.com/whowechina/iidx_teeny/main/doc/main.jpg" width="220px"> <img src="https://raw.githubusercontent.com/whowechina/iidx_teeny/main/doc/main.jpg" width="220px">
* Chu Pico: https://github.com/whowechina/chu_pico * Chu Pico: https://github.com/whowechina/chu_pico
<img src="https://raw.githubusercontent.com/whowechina/chu_pico/main/doc/main.jpg" width="250px"> <img src="https://raw.githubusercontent.com/whowechina/chu_pico/main/doc/main.jpg" width="250px">
* Mai Pico: https://github.com/whowechina/mai_pico * Mai Pico: https://github.com/whowechina/mai_pico
<img src="https://raw.githubusercontent.com/whowechina/mai_pico/main/doc/main.jpg" width="250px"> <img src="https://raw.githubusercontent.com/whowechina/mai_pico/main/doc/main.jpg" width="250px">
## **Disclaimer** ## ## **Disclaimer** ##
I made this project in my personal time with no financial benefit or sponsorship. I will continue to improve the project. I have done my best to ensure that everything is accurate and functional, there's always a chance that mistakes may occur. I cannot be held responsible for any loss of your time or money that may result from using this open source project. Thank you for your understanding. I made this project in my personal time with no financial benefit or sponsorship. I will continue to improve the project. I have done my best to ensure that everything is accurate and functional, there's always a chance that mistakes may occur. I cannot be held responsible for any loss of your time or money that may result from using this open source project. Thank you for your understanding.
## HOW TO BUILD ## HOW TO BUILD
### Turntable Materials ### Turntable Materials
* 1x AS5600 hall angular sensor board set (23mm\*23mm) * 1x AS5600 hall angular sensor board set (23mm\*23mm)
<img src="doc/as5600.png" width="150px"> <img src="doc/as5600.png" width="150px">
* 1x 6mm\*2mm magnet (must be radially magnetized), normally comes with the AS5600 board set. * 1x 6mm\*2mm magnet (must be radially magnetized), normally comes with the AS5600 board set.
* 1x 61804-2RS deep groove ball bearing (20x32x7mm), normally < 5US$; * 1x 61804-2RS deep groove ball bearing (20x32x7mm), normally < 5US$;
* 1x WS2812B LED ring board, or RGB LED strip (recommended). Choose ones with dense LED arrangement (>=32 LEDs per board, or >90 LEDS per meter); * 1x WS2812B LED ring board, or RGB LED strip (recommended). Choose ones with dense LED arrangement (>=32 LEDs per board, or >90 LEDS per meter);
* 3x M4*10mm screws (large flat head is better) and hex nuts, for bearing. For hinge version, use M3 screws. * 3x M4*10mm screws (large flat head is better) and hex nuts, for bearing. For hinge version, use M3 screws.
* 4x M3*12mm screws, for spinning disc. * 4x M3*12mm screws, for spinning disc.
* 1x REF3030 (3.0V Voltage Reference, SOT-23-3). * 1x REF3030 (3.0V Voltage Reference, SOT-23-3).
* 1x Custom cut black acrylic disc, 4mm thickness. * 1x Custom cut black acrylic disc, 4mm thickness.
* 11x 12mm non slip self-adhesive silicon pads (also for Keyboard). * 11x 12mm non slip self-adhesive silicon pads (also for Keyboard).
https://www.amazon.com/Cabinet-Dampening-Adhesive-Circular-Stoppers/dp/B07XXWG818 https://www.amazon.com/Cabinet-Dampening-Adhesive-Circular-Stoppers/dp/B07XXWG818
### Keyboard Materials ### Keyboard Materials
* 1x Raspberry Pi Pico. * 1x Raspberry Pi Pico.
https://www.raspberrypi.com/products/raspberry-pi-pico https://www.raspberrypi.com/products/raspberry-pi-pico
* 11x Kailh Choc v1 or v2 key switches, to get better play feel, 7 of them should be 50g linear. * 11x Kailh Choc v1 or v2 key switches, to get better play feel, 7 of them should be 50g linear.
https://www.kailhswitch.com/mechanical-keyboard-switches/low-profile-key-switches/burnt-orange-switch.html https://www.kailhswitch.com/mechanical-keyboard-switches/low-profile-key-switches/burnt-orange-switch.html
https://www.kailhswitch.com/mechanical-keyboard-switches/key-switches/kailh-low-profile-switch-choc-v2.html https://www.kailhswitch.com/mechanical-keyboard-switches/key-switches/kailh-low-profile-switch-choc-v2.html
* 7x Kailh low-profile stabilizers. * 7x Kailh low-profile stabilizers.
https://chosfox.com/products/kailh-1350-choc-switch-6-25u-stabilizer-set https://chosfox.com/products/kailh-1350-choc-switch-6-25u-stabilizer-set
* 2x Panasonic 6mm square tactile switch EVQP1K05M. * 2x Panasonic 6mm square tactile switch EVQP1K05M.
https://www3.panasonic.biz/ac/e/dl/catalog/index.jsp?series_cd=3473&part_no=EVQP1K05M https://www3.panasonic.biz/ac/e/dl/catalog/index.jsp?series_cd=3473&part_no=EVQP1K05M
* 1x USB Type-C socket (918-418K2023S40001 or KH-TYPE-C-16P) * 1x USB Type-C socket (918-418K2023S40001 or KH-TYPE-C-16P)
* 11x WS2812B-3528 RGB LEDs or if you want more challenge: 28x WS2812B-1516. * 11x WS2812B-3528 RGB LEDs or if you want more challenge: 28x WS2812B-1516.
* 2x SN74LV1T34DBVR (SOT-23-5) level shifter, optional, for better voltage tolerance. * 2x SN74LV1T34DBVR (SOT-23-5) level shifter, optional, for better voltage tolerance.
* 2x 0603 10ohm resistors to bypass said level shifters, optional. * 2x 0603 10ohm resistors to bypass said level shifters, optional.
* 1x 0603 5.1kohm resistors for USB. * 1x 0603 5.1kohm resistors for USB.
* 5x 0805 1uF capacitors. * 5x 0805 1uF capacitors.
* 4x Kailh low-profile keycaps. * 4x Kailh low-profile keycaps.
* 4x M3*6mm screws and hex nuts to fix parts together. * 4x M3*6mm screws and hex nuts to fix parts together.
### Detachable Cable ### Detachable Cable
* 1x HDMI cable (ultra slim, diameter < 4mm), at least 50cm in length, we'll cut the HDMI connectors off, so pick a cheap one. * 1x HDMI cable (ultra slim, diameter < 4mm), at least 50cm in length, we'll cut the HDMI connectors off, so pick a cheap one.
* 2X Magnetic pogopin connector sets, male and female. PCB side should use ones with 90-degree pins, cable side use ones with straight pins. * 2X Magnetic pogopin connector sets, male and female. PCB side should use ones with 90-degree pins, cable side use ones with straight pins.
<img src="doc/pogopin.jpg" width="300px"> <img src="doc/pogopin.jpg" width="300px">
### Step 1 - Buy ### Step 1 - Buy
* Keyboard PCB * Keyboard PCB
Just go [JLC](https://jlcpcb.com/) and make the order. Make sure the board thickness is **1.2mm**, it's very important! Just go [JLC](https://jlcpcb.com/) and make the order. Make sure the board thickness is **1.2mm**, it's very important!
* Turntable PCB * Turntable PCB
It's an optional one. It makes the wiring and soldering inside the turntable a litter easier. It's an optional one. It makes the wiring and soldering inside the turntable a litter easier.
* Acrylic disc * Acrylic disc
Choose the dxf file according to your disc size and find a vendor to cut the 4mm black acrylic. Choose the dxf file according to your disc size and find a vendor to cut the 4mm black acrylic.
### Step 2 - 3D Print ### Step 2 - 3D Print
#### Keyboard #### Keyboard
* PCB bottom (pcb_bottom_*.stl, choose one according to your connector or hinge choice) * PCB bottom (pcb_bottom_*.stl, choose one according to your connector or hinge choice)
FDM, PLA/PETG transparent, 0.2mm layer, 4 walls. FDM, PLA/PETG transparent, 0.2mm layer, 4 walls.
* PCB top (pcb_top.stl) * PCB top (pcb_top.stl)
FDM, PLA transparent, 0.2mm layer, 4 walls. FDM, PLA transparent, 0.2mm layer, 4 walls.
If you have Bambu Lab's AMS system, use PLA black/gray for 3.0mm+ layers. If you have Bambu Lab's AMS system, use PLA black/gray for 3.0mm+ layers.
#### Turntable #### Turntable
For following prints, FDM, PLA, 0.4 nozzle, 0.16-0.2mm layer, 4 walls. And very important: "Seam Position" should be set to "**Random**" in your slicer, not only it looks better, it makes the bearing-flange coupling smoother and tension distributed more evenly. For following prints, FDM, PLA, 0.4 nozzle, 0.16-0.2mm layer, 4 walls. And very important: "Seam Position" should be set to "**Random**" in your slicer, not only it looks better, it makes the bearing-flange coupling smoother and tension distributed more evenly.
These are all printed with These are all printed with
* Base (TT_base_xxx.stl), choose one of the 150, 170 or 180, based on your choice of disc size, 20-60% fill. * Base (TT_base_xxx.stl), choose one of the 150, 170 or 180, based on your choice of disc size, 20-60% fill.
* Bearing seat (bearing_seat_6804.stl), 20-60% fill. * Bearing seat (bearing_seat_6804.stl), 20-60% fill.
* Flange for disc (TTshaft_6804.stl), 60% fill. * Flange for disc (TTshaft_6804.stl), 60% fill.
* If you opt for the hinge option, go with the files with "hinge" in the filename. * If you opt for the hinge option, go with the files with "hinge" in the filename.
#### Pogopin Connector #### Pogopin Connector
It's very small and requires higher accuracy. It's very small and requires higher accuracy.
* Housing for pogopin connector (pogo_bottom.stl, pogo_top.stl). * Housing for pogopin connector (pogo_bottom.stl, pogo_top.stl).
FDM, PLA, **0.2 nozzle** is recommended, 0.1mm layer, 4 walls, 60% fill. FDM, PLA, **0.2 nozzle** is recommended, 0.1mm layer, 4 walls, 60% fill.
#### Button keycaps #### Button keycaps
* Option 1 (Choc V1 or V2): SLA (resin), regular white, 0.05mm layer, check out my orientation: * Option 1 (Choc V1 or V2): SLA (resin), regular white, 0.05mm layer, check out my orientation:
<img src="doc/keycap_support.png" width="300px"> <img src="doc/keycap_support.png" width="300px">
* Option 2 (Choc V2 only): FDM, PLA white, 0.2mm nozzle recommended but 0.4mm nozzle works too, 0.10~0.16mm layer, use easy-to-remove material for support, like "Bambu Support W" or just PETG. * Option 2 (Choc V2 only): FDM, PLA white, 0.2mm nozzle recommended but 0.4mm nozzle works too, 0.10~0.16mm layer, use easy-to-remove material for support, like "Bambu Support W" or just PETG.
<img src="doc/keycap_fdm_1.jpg" width="300px"> <img src="doc/keycap_fdm_1.jpg" width="300px">
<img src="doc/keycap_fdm_2.jpg" width="300px"> <img src="doc/keycap_fdm_2.jpg" width="300px">
### Step 3 - Solder ### Step 3 - Solder
* Keyboard * Keyboard
* WS2812 choices for main 7 main keys, for each key: solder 1x WS2812B-3528 under the key switch, or 4x WS2812-1516 around the key switch. * WS2812 choices for main 7 main keys, for each key: solder 1x WS2812B-3528 under the key switch, or 4x WS2812-1516 around the key switch.
* IMPORTANT: be careful about the orientation of LEDs, they're different at different rows or columns. * IMPORTANT: be careful about the orientation of LEDs, they're different at different rows or columns.
<img src="doc/led_3528_orientation.jpg" width="300px"> <img src="doc/led_3528_orientation.jpg" width="300px">
<img src="doc/led_1615_orientation.jpg" width="300px"> <img src="doc/led_1615_orientation.jpg" width="300px">
* Connector choices: solder 2x pogopin connectors, or solder 1x 3.5mm headphone input jack. * Connector choices: solder 2x pogopin connectors, or solder 1x 3.5mm headphone input jack.
* It's very easy to miss the USB pins of the Raspberry Pico Pi, it's at the other side. And it's difficult to solder as you may leave an airbubble in the soldering hole. My trick is to use sharpest iron tip, super-slowly apply solder wire only at one side. This is my result: * It's very easy to miss the USB pins of the Raspberry Pico Pi, it's at the other side. And it's difficult to solder as you may leave an airbubble in the soldering hole. My trick is to use sharpest iron tip, super-slowly apply solder wire only at one side. This is my result:
<img src="doc/solder_usb_txrx.jpg" width="300px"> <img src="doc/solder_usb_txrx.jpg" width="300px">
* You can use level shifter (SN74LV1T34DBVR, U2/U3), or you can just bypass it by soldering a nearby resistor (10 ohm, R1/R2). * You can use level shifter (SN74LV1T34DBVR, U2/U3), or you can just bypass it by soldering a nearby resistor (10 ohm, R1/R2).
* Optional: TVS1 and TVS2 are rated 3.3V, protecting GPIOs. TVS3 should be rated 5V when using level shifter, and 3.3V when not using level shifter. * Optional: TVS1 and TVS2 are rated 3.3V, protecting GPIOs. TVS3 should be rated 5V when using level shifter, and 3.3V when not using level shifter.
* Turntable * Turntable
* General * General
Typical AS5600 development board comes with 3.3V configuration, we can't feed 5V to it directly, it would burn the AS5600 or the main Pi Pico. The GPIO we use to communicate with AS5600 can never go beyond 3.6V. So we need a lower voltage, I chose REF3030, a precise 3.0V voltage reference. Typical AS5600 development board comes with 3.3V configuration, we can't feed 5V to it directly, it would burn the AS5600 or the main Pi Pico. The GPIO we use to communicate with AS5600 can never go beyond 3.6V. So we need a lower voltage, I chose REF3030, a precise 3.0V voltage reference.
You need to scrape off some solder mask to expose the ground copper (don't scrape the solder mask under 5V pin). I found a good place to mount the REF3030, this is how I handled it: You need to scrape off some solder mask to expose the ground copper (don't scrape the solder mask under 5V pin). I found a good place to mount the REF3030, this is how I handled it:
<img src="doc/ref3030.jpg" width="300px"> <img src="doc/ref3030.jpg" width="300px">
* **Very Important** * **Very Important**
Before proceeding further, it's important to know that the silicone hinge option used in my IIDX Teeny has proven to be the most effective and stable. Therefore, it's highly recommended to opt for the hinge option, rather than the subsequent digital (pogopin). I've also removed the analog (3.5mm headphone jack) option simply because it's not good. If you use Teeny's silicone hinge option, use the added J3/J4 3.3v soldering pads to power the AS5600. Before proceeding further, it's important to know that the silicone hinge option used in my IIDX Teeny has proven to be the most effective and stable. Therefore, it's highly recommended to opt for the hinge option, rather than the subsequent digital (pogopin). I've also removed the analog (3.5mm headphone jack) option simply because it's not good. If you use Teeny's silicone hinge option, use the added J3/J4 3.3v soldering pads to power the AS5600.
* If you go with digital (magnetic pogo pin connector) * If you go with digital (magnetic pogo pin connector)
There're a set of I2C and a WS2812B signal line together in the cable that connects turntable and the keyboard. Unfortunately, these signals crosstalk. So, we have to use shield cables for them. Two I2C lines should have a shield cable, and the WS2812B signal should have another shield cable. Good thing is, an HDMI cable has 4 shield cables and bunch of other small cables. We can make use of it. There're a set of I2C and a WS2812B signal line together in the cable that connects turntable and the keyboard. Unfortunately, these signals crosstalk. So, we have to use shield cables for them. Two I2C lines should have a shield cable, and the WS2812B signal should have another shield cable. Good thing is, an HDMI cable has 4 shield cables and bunch of other small cables. We can make use of it.
<img src="doc/pogopin_wiring.jpg" width="300px"> <img src="doc/pogopin_wiring.jpg" width="300px">
* Turntable LED Ring * Turntable LED Ring
I recommend to use LED strip over LED board, becuase the LED board's light is facing up, but using strip, the light can spread out pefectly. I recommend to use LED strip over LED board, becuase the LED board's light is facing up, but using strip, the light can spread out pefectly.
Use transparent double-sided tape to stick the LED around the turntable inner wall. Use transparent double-sided tape to stick the LED around the turntable inner wall.
### Step 4 - Assemble ### Step 4 - Assemble
* Assemble the turntable * Assemble the turntable
I don't know how to draw an explosion diagram, this is done by coding in OpenSCAD: I don't know how to draw an explosion diagram, this is done by coding in OpenSCAD:
<img src="doc/tt_assemble.png" width="500px"> <img src="doc/tt_assemble.png" width="500px">
These shows how a bearing is installed. These shows how a bearing is installed.
<img src="doc/bearing_1.jpg" width="300px"> <img src="doc/bearing_1.jpg" width="300px">
<img src="doc/bearing_2.jpg" width="300px"> <img src="doc/bearing_2.jpg" width="300px">
<img src="doc/bearing_3.jpg" width="300px"> <img src="doc/bearing_3.jpg" width="300px">
<img src="doc/bearing_4.jpg" width="300px"> <img src="doc/bearing_4.jpg" width="300px">
<img src="doc/bearing_5.jpg" width="300px"> <img src="doc/bearing_5.jpg" width="300px">
* Install the low-profile stabilizers. * Install the low-profile stabilizers.
https://docs.keeb.io/choc-stabs https://docs.keeb.io/choc-stabs
A little trick here. As the PCB footprint is made to support both choc v1 and v2, that leaves some wobble space for choc v1 and makes it difficult to align. So leave the key switch unsoldered, when the stabilizer, the key switch and the keycap are all in place, push the keycap down and then solder the key switch. This way the key switch will be aligned to the stabilizers better. A little trick here. As the PCB footprint is made to support both choc v1 and v2, that leaves some wobble space for choc v1 and makes it difficult to align. So leave the key switch unsoldered, when the stabilizer, the key switch and the keycap are all in place, push the keycap down and then solder the key switch. This way the key switch will be aligned to the stabilizers better.
* Assemble the keyboard * Assemble the keyboard
It's very easy. It's very easy.
<img src="doc/kb_assemble.png" width="500px"> <img src="doc/kb_assemble.png" width="500px">
<img src="doc/kb_1.jpg" width="300px"> <img src="doc/kb_1.jpg" width="300px">
<img src="doc/kb_2.jpg" width="300px"> <img src="doc/kb_2.jpg" width="300px">
<img src="doc/kb_3.jpg" width="300px"> <img src="doc/kb_3.jpg" width="300px">
<img src="doc/kb_4.jpg" width="300px"> <img src="doc/kb_4.jpg" width="300px">
<img src="doc/kb_5.jpg" width="300px"> <img src="doc/kb_5.jpg" width="300px">
### Step 4 - Firmware ### Step 4 - Firmware
* For the new build, hold the BOOTSEL button while connect the USB to a PC, there will be a disk named "RPI-RP2" showed up. Drag the uf2 firmware binary file into it. That's it. There's a small hole at the back side of the keyboard, it is facing right to the BOOTSEL button. * For the new build, hold the BOOTSEL button while connect the USB to a PC, there will be a disk named "RPI-RP2" showed up. Drag the uf2 firmware binary file into it. That's it. There's a small hole at the back side of the keyboard, it is facing right to the BOOTSEL button.
* If it is already running my IIDX firmware, hold two small AUX buttons together will do the same as the BOOTSEL button. * If it is already running my IIDX firmware, hold two small AUX buttons together will do the same as the BOOTSEL button.
* You need to setup your configuration such as AS5600 connection mode and LED ring. * You need to setup your configuration such as AS5600 connection mode and LED ring.
* Also you can setup the key color theme and turntable effects at runtime. I think I made the configuration too showey and complicated. Check out the manual. * Also you can setup the key color theme and turntable effects at runtime. I think I made the configuration too showey and complicated. Check out the manual.
[Nice Looking Manual Here](doc/Firmware_manual.pdf) [Nice Looking Manual Here](doc/Firmware_manual.pdf)
<img src="doc/manual.gif" width="80%"> <img src="doc/manual.gif" width="80%">
### What If? ### What If?
* I can't find pogopin connector. * I can't find pogopin connector.
**Solution:** I figured out some another choices, one is using a 3.5mm 4P headphone jack. It uses analog to communicate turntable movements, but I'm still testing it, so stay tuned. I will update this document. The other is to use fixed connection (left or right hinge). **Solution:** I figured out some another choices, one is using a 3.5mm 4P headphone jack. It uses analog to communicate turntable movements, but I'm still testing it, so stay tuned. I will update this document. The other is to use fixed connection (left or right hinge).
* I don't have Bambu Lab's machine, or I don't have an AMS system. * I don't have Bambu Lab's machine, or I don't have an AMS system.
**Solution:** There're many online vendors and people providing paid Bambu printing service. Or you can just use other 3D printers. It's just the numbers in the OpenSCAD source file or STL files are finetuned on my Bambu Lab X1. You may need to adjust a little on your 3D printer system to get perfect result. And regarding the multi-color thing, maybe you can just paint the top layer by hand. I know people do miniature painting, I think it would be similar. **Solution:** There're many online vendors and people providing paid Bambu printing service. Or you can just use other 3D printers. It's just the numbers in the OpenSCAD source file or STL files are finetuned on my Bambu Lab X1. You may need to adjust a little on your 3D printer system to get perfect result. And regarding the multi-color thing, maybe you can just paint the top layer by hand. I know people do miniature painting, I think it would be similar.
* STL files are not accurate, difficult to assemble. * STL files are not accurate, difficult to assemble.
**Solution:** 3D printer systems are different one from another, it results in small differences even with same model file and some configuration. If the printed parts are not happy with each other, you can fiddle with the OpenSCAD source file and the numbers in it for your case. **Solution:** 3D printer systems are different one from another, it results in small differences even with same model file and some configuration. If the printed parts are not happy with each other, you can fiddle with the OpenSCAD source file and the numbers in it for your case.
* I don't have resin printer. * I don't have resin printer.
* I can't find Kailh low-profile stabilizer. * I can't find Kailh low-profile stabilizer.
* I don't have electronic DIY gears. * I don't have electronic DIY gears.
**Solution:** OK, this is an electronic hobby project, maybe it's not for you if you don't plan to do electronic DIYs. There're many good IIDX controllers you can purchase somewhere online. **Solution:** OK, this is an electronic hobby project, maybe it's not for you if you don't plan to do electronic DIYs. There're many good IIDX controllers you can purchase somewhere online.
* I want Bluetooth support. * I want Bluetooth support.
**Not A Solution:** I once wanted to implement the Bluetooth support. But after I tried bluetooth joystick, I gave up. You really don't want to play rhythm game with a Bluetooth connection! **Not A Solution:** I once wanted to implement the Bluetooth support. But after I tried bluetooth joystick, I gave up. You really don't want to play rhythm game with a Bluetooth connection!

View File

@ -1,195 +1,196 @@
/* /*
* The MIT License (MIT) * The MIT License (MIT)
* *
* Copyright (c) 2019 Ha Thach (tinyusb.org) * Copyright (c) 2019 Ha Thach (tinyusb.org)
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
* *
*/ */
#include "usb_descriptors.h" #include "usb_descriptors.h"
#include "tusb.h" #include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save /* A combination of interfaces must have a unique product id, since PC will save
* device driver after the first plug. Same VID/PID with different interface e.g * device driver after the first plug. Same VID/PID with different interface e.g
* MSC (first), then CDC (later) will possibly cause system error on PC. * MSC (first), then CDC (later) will possibly cause system error on PC.
* *
* Auto ProductID layout's Bitmap: * Auto ProductID layout's Bitmap:
* [MSB] HID | MSC | CDC [LSB] * [MSB] HID | MSC | CDC [LSB]
*/ */
#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n)) #define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
#define USB_PID \ #define USB_PID \
(0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4)) _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4))
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Device Descriptors // Device Descriptors
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
tusb_desc_device_t desc_device_joy = { tusb_desc_device_t desc_device_joy = {
.bLength = sizeof(tusb_desc_device_t), .bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE, .bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200, .bcdUSB = 0x0200,
.bDeviceClass = 0x00, .bDeviceClass = 0x00,
.bDeviceSubClass = 0x00, .bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00, .bDeviceProtocol = 0x00,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCaff, .idVendor = 0xCaff,
.idProduct = USB_PID, .idProduct = USB_PID,
.bcdDevice = 0x0100, .bcdDevice = 0x0100,
.iManufacturer = 0x01, .iManufacturer = 0x01,
.iProduct = 0x02, .iProduct = 0x02,
.iSerialNumber = 0x03, .iSerialNumber = 0x03,
.bNumConfigurations = 0x01}; .bNumConfigurations = 0x01};
// Invoked when received GET DEVICE DESCRIPTOR // Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor // Application return pointer to descriptor
uint8_t const* tud_descriptor_device_cb(void) { uint8_t const* tud_descriptor_device_cb(void) {
return (uint8_t const*)&desc_device_joy; return (uint8_t const*)&desc_device_joy;
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// HID Report Descriptor // HID Report Descriptor
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
uint8_t const desc_hid_report_joy[] = { uint8_t const desc_hid_report_joy[] = {
GAMECON_REPORT_DESC_JOYSTICK(HID_REPORT_ID(REPORT_ID_JOYSTICK)), GAMECON_REPORT_DESC_JOYSTICK(HID_REPORT_ID(REPORT_ID_JOYSTICK)),
GAMECON_REPORT_DESC_LIGHTS(HID_REPORT_ID(REPORT_ID_LIGHTS)) GAMECON_REPORT_DESC_LIGHTS(HID_REPORT_ID(REPORT_ID_LIGHTS))
}; };
// Invoked when received GET HID REPORT DESCRIPTOR // Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor // Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete // Descriptor contents must exist long enough for transfer to complete
uint8_t const* tud_hid_descriptor_report_cb(uint8_t itf) { uint8_t const* tud_hid_descriptor_report_cb(uint8_t itf) {
(void)itf; (void)itf;
return desc_hid_report_joy; return desc_hid_report_joy;
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Configuration Descriptor // Configuration Descriptor
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
enum { ITF_NUM_HID, ITF_NUM_CDC, ITF_NUM_CDC_DATA, ITF_NUM_TOTAL }; enum { ITF_NUM_HID, ITF_NUM_CDC, ITF_NUM_CDC_DATA, ITF_NUM_TOTAL };
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_CDC_DESC_LEN) #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_CDC_DESC_LEN)
#define EPNUM_HID 0x84 #define EPNUM_HID 0x84
#define EPNUM_CDC_NOTIF 0x81 #define EPNUM_CDC_NOTIF 0x81
#define EPNUM_CDC_OUT 0x02 #define EPNUM_CDC_OUT 0x02
#define EPNUM_CDC_IN 0x82 #define EPNUM_CDC_IN 0x82
uint8_t const desc_configuration_joy[] = { uint8_t const desc_configuration_joy[] = {
// Config number, interface count, string index, total length, attribute, // Config number, interface count, string index, total length, attribute,
// power in mA // power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN,
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
// Interface number, string index, protocol, report descriptor len, EP In // Interface number, string index, protocol, report descriptor len, EP In
// address, size & polling interval // address, size & polling interval
TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE,
sizeof(desc_hid_report_joy), EPNUM_HID, sizeof(desc_hid_report_joy), EPNUM_HID,
CFG_TUD_HID_EP_BUFSIZE, 1), CFG_TUD_HID_EP_BUFSIZE, 1),
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF,
8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64) 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64)
}; };
// Invoked when received GET CONFIGURATION DESCRIPTOR // Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor // Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete // Descriptor contents must exist long enough for transfer to complete
uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
(void)index; // for multiple configurations (void)index; // for multiple configurations
return desc_configuration_joy; return desc_configuration_joy;
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// String Descriptors // String Descriptors
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// array of pointer to string descriptors // array of pointer to string descriptors
const char *string_desc_arr[] = { const char *string_desc_arr[] = {
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
"WHowe" , // 1: Manufacturer "WHowe" , // 1: Manufacturer
"Pico IIDX Controller", // 2: Product "IIDX Pico Controller", // 2: Product
"654321", // 3: Serials, should use chip ID "654321", // 3: Serials, should use chip ID
"Button 1", "IIDX Pico CLI Port",
"Button 2", "Button 1",
"Button 3", "Button 2",
"Button 4", "Button 3",
"Button 5", "Button 4",
"Button 6", "Button 5",
"Button 7", "Button 6",
"E1", "Button 7",
"E2", "E1",
"E3", "E2",
"E4" "E3",
}; "E4"
};
static uint16_t _desc_str[64];
static uint16_t _desc_str[64];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long // Invoked when received GET STRING DESCRIPTOR request
// enough for transfer to complete // Application return pointer to descriptor, whose contents must exist long
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // enough for transfer to complete
(void)langid; uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
(void)langid;
uint8_t chr_count;
uint8_t chr_count;
if (index == 0) {
memcpy(&_desc_str[1], string_desc_arr[0], 2); if (index == 0) {
chr_count = 1; memcpy(&_desc_str[1], string_desc_arr[0], 2);
} else { chr_count = 1;
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. } else {
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if (index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) {
const char* str = string_desc_arr[index]; if (index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) {
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str); // Cap at max char
if (chr_count > 63) chr_count = 63; chr_count = strlen(str);
if (chr_count > 63) chr_count = 63;
// Convert ASCII string into UTF-16
for (uint8_t i = 0; i < chr_count; i++) { // Convert ASCII string into UTF-16
_desc_str[1 + i] = str[i]; for (uint8_t i = 0; i < chr_count; i++) {
} _desc_str[1 + i] = str[i];
} else { }
_desc_str[1] = 'X'; } else {
chr_count = 1; _desc_str[1] = 'X';
} chr_count = 1;
} }
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); // first byte is length (including header), second byte is string type
_desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2);
return _desc_str;
} return _desc_str;
}
void konami_mode()
{ void konami_mode()
desc_device_joy.idVendor = 0x1ccf; {
desc_device_joy.idProduct = 0x8048; desc_device_joy.idVendor = 0x1ccf;
string_desc_arr[1] = "Konami Amusement"; desc_device_joy.idProduct = 0x8048;
string_desc_arr[2] = "beatmania IIDX controller premium model"; string_desc_arr[1] = "Konami Amusement";
} string_desc_arr[2] = "beatmania IIDX controller premium model";
}

View File

@ -1,54 +1,50 @@
#ifndef USB_DESCRIPTORS_H_ #ifndef USB_DESCRIPTORS_H_
#define USB_DESCRIPTORS_H_ #define USB_DESCRIPTORS_H_
#include "common/tusb_common.h" #include "common/tusb_common.h"
#include "device/usbd.h" #include "device/usbd.h"
enum { enum {
REPORT_ID_JOYSTICK = 1, REPORT_ID_JOYSTICK = 1,
REPORT_ID_LIGHTS, REPORT_ID_LIGHTS,
}; };
// because they are missing from tusb_hid.h #define HID_STRING_MINIMUM(x) HID_REPORT_ITEM(x, 8, RI_TYPE_LOCAL, 1)
#define HID_STRING_INDEX(x) HID_REPORT_ITEM(x, 7, RI_TYPE_LOCAL, 1) #define HID_STRING_MAXIMUM(x) HID_REPORT_ITEM(x, 9, RI_TYPE_LOCAL, 1)
#define HID_STRING_INDEX_N(x, n) HID_REPORT_ITEM(x, 7, RI_TYPE_LOCAL, n)
#define HID_STRING_MINIMUM(x) HID_REPORT_ITEM(x, 8, RI_TYPE_LOCAL, 1) // Joystick Report Descriptor Template - Based off Drewol/rp2040-gamecon
#define HID_STRING_MINIMUM_N(x, n) HID_REPORT_ITEM(x, 8, RI_TYPE_LOCAL, n) // Button Map | X | Y
#define HID_STRING_MAXIMUM(x) HID_REPORT_ITEM(x, 9, RI_TYPE_LOCAL, 1) #define GAMECON_REPORT_DESC_JOYSTICK(...) \
#define HID_STRING_MAXIMUM_N(x, n) HID_REPORT_ITEM(x, 9, RI_TYPE_LOCAL, n) HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \
HID_USAGE(HID_USAGE_DESKTOP_JOYSTICK), \
// Joystick Report Descriptor Template - Based off Drewol/rp2040-gamecon HID_COLLECTION(HID_COLLECTION_APPLICATION), \
// Button Map | X | Y __VA_ARGS__ HID_USAGE_PAGE(HID_USAGE_PAGE_BUTTON), HID_USAGE_MIN(1), \
#define GAMECON_REPORT_DESC_JOYSTICK(...) \ HID_USAGE_MAX(13), \
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), \ HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), HID_REPORT_COUNT(13), \
HID_USAGE(HID_USAGE_DESKTOP_JOYSTICK), \ HID_REPORT_SIZE(1), HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
HID_COLLECTION(HID_COLLECTION_APPLICATION), \ HID_REPORT_COUNT(1), HID_REPORT_SIZE(16 - 13), /*Padding*/ \
__VA_ARGS__ HID_USAGE_PAGE(HID_USAGE_PAGE_BUTTON), HID_USAGE_MIN(1), \ HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \
HID_USAGE_MAX(13), \ HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_LOGICAL_MIN(0x00), \
HID_LOGICAL_MIN(0), HID_LOGICAL_MAX(1), HID_REPORT_COUNT(13), \ HID_LOGICAL_MAX_N(0x00ff, 2), /* Below is Joystick/analog */ \
HID_REPORT_SIZE(1), HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \ HID_USAGE(HID_USAGE_DESKTOP_X), HID_USAGE(HID_USAGE_DESKTOP_Y), \
HID_REPORT_COUNT(1), HID_REPORT_SIZE(16 - 13), /*Padding*/ \ HID_REPORT_COUNT(2), HID_REPORT_SIZE(8), \
HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \ HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), HID_COLLECTION_END
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_LOGICAL_MIN(0x00), \
HID_LOGICAL_MAX_N(0x00ff, 2), /* Below is Joystick/analog */ \ // Light Map
HID_USAGE(HID_USAGE_DESKTOP_X), HID_USAGE(HID_USAGE_DESKTOP_Y), \ #define GAMECON_REPORT_DESC_LIGHTS(...) \
HID_REPORT_COUNT(2), HID_REPORT_SIZE(8), \ HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), HID_COLLECTION_END HID_COLLECTION(HID_COLLECTION_APPLICATION), \
__VA_ARGS__ HID_REPORT_COUNT(11), /* LED NUM */ \
// Light Map HID_REPORT_SIZE(8), HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \
#define GAMECON_REPORT_DESC_LIGHTS(...) \ HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), \
HID_USAGE_PAGE(HID_USAGE_PAGE_DESKTOP), HID_USAGE(0x00), \ HID_STRING_MINIMUM(5), HID_STRING_MAXIMUM(17), \
HID_COLLECTION(HID_COLLECTION_APPLICATION), \ HID_USAGE_MIN(1), HID_USAGE_MAX(16), \
__VA_ARGS__ HID_REPORT_COUNT(11), /* LED NUM */ \ HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), HID_REPORT_COUNT(1), \
HID_REPORT_SIZE(8), HID_LOGICAL_MIN(0x00), HID_LOGICAL_MAX_N(0x00ff, 2), \ HID_REPORT_SIZE(8), /*Padding*/ \
HID_USAGE_PAGE(HID_USAGE_PAGE_ORDINAL), HID_STRING_MINIMUM(4), \ HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \
HID_STRING_MAXIMUM(16), HID_USAGE_MIN(1), HID_USAGE_MAX(16), \ HID_COLLECTION_END
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), HID_REPORT_COUNT(1), \
HID_REPORT_SIZE(8), /*Padding*/ \ /* Enable Konami spoof mode */
HID_INPUT(HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE), \ void konami_mode();
HID_COLLECTION_END
/* Enable Konami spoof mode */
void konami_mode();
#endif /* USB_DESCRIPTORS_H_ */ #endif /* USB_DESCRIPTORS_H_ */