main.c 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // PicoPuck main — core0 cooperative loop.
  2. //
  3. // Presents either the Valve puck (Steam/Lizard) or an emulated controller
  4. // (Xbox/Switch/PS5/PS3/…) over USB, fed by controllers connected over Bluetooth.
  5. // The active mode is loaded from flash at boot; switching it persists + reboots.
  6. //
  7. // SPDX-License-Identifier: AGPL-3.0-or-later
  8. #include "config/picopuck_config.h"
  9. #include "config/modes.h"
  10. #include "puck/identity.h"
  11. #include "puck/slots.h"
  12. #include "puck/personality.h"
  13. #include "puck/emu_present.h"
  14. #include "puck/xinput.h"
  15. #include "usb_mount.h"
  16. #include "usb/usb_tx.h"
  17. #include "usb/usb_descriptors.h"
  18. #include "usb/webusb.h"
  19. #include "bt/bt_host.h"
  20. #include "sys/settings.h"
  21. #include "pico/stdlib.h"
  22. #include "pico/cyw43_arch.h"
  23. #include "hardware/watchdog.h"
  24. #include "tusb.h"
  25. int main(void)
  26. {
  27. stdio_init_all();
  28. settings_load(); // active USB mode (before descriptors)
  29. identity_init();
  30. slots_init();
  31. puck_personality_init();
  32. webusb_init();
  33. // Build the descriptor set for the active mode, then start USB.
  34. usb_descriptors_init();
  35. tud_init(0);
  36. bool puck = mode_is_puck(settings_mode());
  37. bool xinput = mode_is_xinput(settings_mode());
  38. // HID emulated modes present one gamepad per CONNECTED controller, mounted /
  39. // unmounted dynamically (no reboot) — same behaviour as OpenPuck. Puck and
  40. // XInput modes keep their fixed interface layout.
  41. if (!puck && !xinput)
  42. usb_mount_enable(true, PP_NSLOT);
  43. // The user LED hangs off the CYW43 chip; this init also hands the radio to
  44. // BTstack (btstack_cyw43_init on the async_context).
  45. bool have_radio = (cyw43_arch_init() == 0);
  46. bool have_bt = have_radio && bt_host_init();
  47. printf("\n[picopuck] boot commit=%s board=%d mode=%d radio=%d bt=%d\n",
  48. PICOPUCK_GIT_COMMIT, PP_BOARD, settings_mode(), have_radio,
  49. have_bt);
  50. watchdog_enable(PP_WATCHDOG_MS, /*pause_on_debug=*/true);
  51. absolute_time_t next_led = make_timeout_time_ms(PP_STATUS_LED_MS);
  52. bool led_on = false;
  53. while (1) {
  54. tud_task(); // USB device events
  55. usb_tx_pump(); // drain queued HID reports
  56. if (puck)
  57. puck_personality_task(); // puck 0x79 / 0x7B / 0x43 + synth stream
  58. else if (xinput)
  59. xinput_task(); // Xbox 360 XInput report stream
  60. else
  61. emu_present_task(); // emulated controller report stream
  62. usb_mount_task(); // dynamic mount/unmount on connect/disconnect (emu modes)
  63. webusb_task(); // panel commands (works in every mode)
  64. if (have_bt) {
  65. cyw43_arch_poll(); // services BTstack on its async_context
  66. bt_host_task(); // scan / battery / rssi / rumble
  67. } else if (have_radio) {
  68. cyw43_arch_poll();
  69. }
  70. if (absolute_time_diff_us(get_absolute_time(), next_led) <= 0) {
  71. led_on = !led_on;
  72. if (have_radio)
  73. cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN,
  74. led_on);
  75. next_led = make_timeout_time_ms(PP_STATUS_LED_MS);
  76. }
  77. watchdog_update();
  78. }
  79. return 0;
  80. }