diff --git a/README.md b/README.md index f1b0f9b2..a2075eb9 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,14 @@ where (brace yourself) most things actually work. ``` - [FPVue_android](https://github.com/gehee/FPVue_android): basic and unique work to combine all components into a single application by [Gee He](https://github.com/gehee). -- [devourer](https://github.com/openipc/devourer): userspace rtl8812au driver initially created by [buldo](https://github.com/buldo) and converted to C by [josephnef](https://github.com/josephnef). +- [devourer](https://github.com/openipc/devourer): userspace Realtek 11ac driver (rtl8812au + rtl8812eu) initially created by [buldo](https://github.com/buldo) and converted to C by [josephnef](https://github.com/josephnef). - [LiveVideo10ms](https://github.com/Consti10/LiveVideo10ms): excellent video decoder from [Consti10](https://github.com/Consti10) converted into a module. - [wfb-ng](https://github.com/svpcom/wfb-ng): library allowing the broadcast of the video feed over the air. The wfb-ng [gs.key](https://github.com/OpenIPC/PixelPilot/raw/main/app/src/main/assets/gs.key) is embedded in the app. The settings menu allows selecting a different key from your phone. -Supported rtl8812au wifi adapter are listed [here](https://github.com/OpenIPC/PixelPilot/blob/master/app/src/main/res/xml/usb_device_filter.xml). +Supported rtl8812au and rtl8812eu wifi adapters are listed [here](https://github.com/OpenIPC/PixelPilot/blob/master/app/src/main/res/xml/usb_device_filter.xml). Feel free to send pull requests to add new supported wifi adapters hardware IDs. Now support saving a dvr of the video feed to `Files/Internal Storage/Movies/` diff --git a/app/src/main/res/xml/usb_device_filter.xml b/app/src/main/res/xml/usb_device_filter.xml index f230ca27..d3c40a60 100644 --- a/app/src/main/res/xml/usb_device_filter.xml +++ b/app/src/main/res/xml/usb_device_filter.xml @@ -33,4 +33,13 @@ + + + diff --git a/app/wfbngrtl8812/src/main/cpp/CMakeLists.txt b/app/wfbngrtl8812/src/main/cpp/CMakeLists.txt index 42811e99..a7320129 100644 --- a/app/wfbngrtl8812/src/main/cpp/CMakeLists.txt +++ b/app/wfbngrtl8812/src/main/cpp/CMakeLists.txt @@ -26,47 +26,73 @@ target_compile_definitions(wfb-ng PRIVATE ZFEX_INLINE_ADDMUL_SIMD ) +# devourer — userspace Realtek 11ac driver. Mirrors the source groups of +# devourer's own CMakeLists.txt (which we can't add_subdirectory here because +# it resolves libusb via pkg-config, unavailable in the NDK build). +# Chip support compiled in: +# Jaguar1 (RTL8812AU / 8811AU / 8821AU) — the classic PixelPilot adapters +# Jaguar3 8822E (RTL8812EU / RTL8822EU) — e.g. LB-LINK BL-M8812EU2 add_library(devourer STATIC - ${CMAKE_SOURCE_DIR}/devourer/hal/Hal8812PhyReg.h - ${CMAKE_SOURCE_DIR}/devourer/hal/Hal8812PwrSeq.c - ${CMAKE_SOURCE_DIR}/devourer/hal/Hal8812PwrSeq.h - ${CMAKE_SOURCE_DIR}/devourer/hal/basic_types.h + # --- generation-agnostic core --- + ${CMAKE_SOURCE_DIR}/devourer/src/ParsedRadioPacket.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/Radiotap.c + ${CMAKE_SOURCE_DIR}/devourer/src/RadiotapBuilder.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/RtlAdapter.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/UsbTransport.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/UsbDeviceLock.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/UsbOpen.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/TxMode.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/TxPower.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/LinkHealth.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/SignalStop.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/WiFiDriver.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/PhyTableLoader.cpp + + # --- Jaguar1 (RTL8812AU / 8811AU / 8821AU) --- ${CMAKE_SOURCE_DIR}/devourer/hal/hal8812a_fw.c - ${CMAKE_SOURCE_DIR}/devourer/hal/hal8812a_fw.h - ${CMAKE_SOURCE_DIR}/devourer/hal/hal_com_reg.h - ${CMAKE_SOURCE_DIR}/devourer/hal/rtl8812a_hal.h - ${CMAKE_SOURCE_DIR}/devourer/hal/rtl8812a_recv.h - ${CMAKE_SOURCE_DIR}/devourer/hal/rtl8812a_spec.h + ${CMAKE_SOURCE_DIR}/devourer/hal/hal8821a_fw.c + ${CMAKE_SOURCE_DIR}/devourer/hal/Hal8812PwrSeq.c + ${CMAKE_SOURCE_DIR}/devourer/hal/Hal8821APwrSeq.c + ${CMAKE_SOURCE_DIR}/devourer/hal/Hal8812a_TxPwrTrack.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/RtlJaguarDevice.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/HalModule.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/RadioManagementModule.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/EepromManager.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/FirmwareManager.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/Iqk8812a.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/PhydmWatchdog.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/PowerTracking8812a.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/FrameParser.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar1/BbDbgportReader.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/Radiotap.c - ${CMAKE_SOURCE_DIR}/devourer/src/registry_priv.h - ${CMAKE_SOURCE_DIR}/devourer/src/ieee80211_radiotap.h + # --- Jaguar3 shared (dispatchers compiled for any Jaguar3 variant) --- + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/RtlJaguar3Device.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/HalJaguar3.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/HalmacJaguar3Fw.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/HalmacJaguar3MacInit.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/RadioManagementJaguar3.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/PhyTableLoaderJaguar3.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/Phy8822cTables.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/Halrf8822c.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/EepromManager.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/EepromManager.h - ${CMAKE_SOURCE_DIR}/devourer/src/Firmware.h - ${CMAKE_SOURCE_DIR}/devourer/src/FirmwareManager.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/FirmwareManager.h - ${CMAKE_SOURCE_DIR}/devourer/src/FrameParser.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/FrameParser.h - ${CMAKE_SOURCE_DIR}/devourer/src/HalModule.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/HalModule.h - ${CMAKE_SOURCE_DIR}/devourer/src/ParsedRadioPacket.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/RadioManagementModule.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/RadioManagementModule.h - ${CMAKE_SOURCE_DIR}/devourer/src/Rtl8812aDevice.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/Rtl8812aDevice.h - ${CMAKE_SOURCE_DIR}/devourer/src/RtlUsbAdapter.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/RtlUsbAdapter.h - ${CMAKE_SOURCE_DIR}/devourer/src/SelectedChannel.h - ${CMAKE_SOURCE_DIR}/devourer/src/WiFiDriver.cpp - ${CMAKE_SOURCE_DIR}/devourer/src/WiFiDriver.h - ${CMAKE_SOURCE_DIR}/devourer/src/registry_priv.h) + # --- Jaguar3 8822E variant (RTL8812EU / RTL8822EU) --- + ${CMAKE_SOURCE_DIR}/devourer/hal/hal8822e_fw.c + ${CMAKE_SOURCE_DIR}/devourer/hal/phydm/rtl8822e/Hal8822e_PhyTables.c + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/Phy8822eTables.cpp + ${CMAKE_SOURCE_DIR}/devourer/src/jaguar3/Halrf8822e.cpp) set_target_properties(devourer PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/devourer) +target_compile_definitions(devourer PUBLIC + DEVOURER_HAVE_JAGUAR1=1 + DEVOURER_HAVE_JAGUAR3=1 + DEVOURER_HAVE_JAGUAR3_8822E=1) target_include_directories(devourer PUBLIC ${CMAKE_SOURCE_DIR}/devourer) +target_include_directories(devourer PUBLIC ${CMAKE_SOURCE_DIR}/devourer/src) target_include_directories(devourer PUBLIC ${CMAKE_SOURCE_DIR}/devourer/hal) +target_include_directories(devourer PUBLIC ${CMAKE_SOURCE_DIR}/devourer/hal/phydm/rtl8822c) +target_include_directories(devourer PUBLIC ${CMAKE_SOURCE_DIR}/devourer/hal/phydm/rtl8822e) +target_link_libraries(devourer PUBLIC log) set_property(TARGET devourer PROPERTY CXX_STANDARD 20) # WFB-NG RTL8812 library diff --git a/app/wfbngrtl8812/src/main/cpp/TxFrame.cpp b/app/wfbngrtl8812/src/main/cpp/TxFrame.cpp index 1107e7f5..ac65b2b1 100644 --- a/app/wfbngrtl8812/src/main/cpp/TxFrame.cpp +++ b/app/wfbngrtl8812/src/main/cpp/TxFrame.cpp @@ -3,7 +3,7 @@ #include "sodium/crypto_aead_chacha20poly1305.h" #include "sodium/crypto_box.h" #include "sodium/randombytes.h" -#include "src/Rtl8812aDevice.h" +#include "src/IRtlDevice.h" #include "src/wifibroadcast.hpp" #include "src/zfex.h" @@ -422,7 +422,7 @@ UsbTransmitter::UsbTransmitter(int k, uint8_t *radiotapHeader, size_t radiotapHeaderLen, uint8_t frameType, - Rtl8812aDevice *device) + IRtlDevice *device) : Transmitter(k, n, keypair, epoch, channelId), channelId_(channelId), currentOutput_(0), ieee80211Sequence_(0), radiotapHeader_(radiotapHeader), radiotapHeaderLen_(radiotapHeaderLen), frameType_(frameType), rtlDevice_(device) { @@ -467,11 +467,11 @@ void UsbTransmitter::dumpStats( } void UsbTransmitter::injectPacket(const uint8_t *buf, size_t size) { - if (!rtlDevice_ || rtlDevice_->should_stop) { + if (!rtlDevice_) { #ifdef __ANDROID__ - __android_log_print(ANDROID_LOG_DEBUG, TAG, "Main thread exited, cannot send packets"); + __android_log_print(ANDROID_LOG_DEBUG, TAG, "No USB device, cannot send packets"); #endif - throw std::runtime_error("USB Transmitter: main thread exit, should stop"); + throw std::runtime_error("USB Transmitter: no device, should stop"); } if (size > MAX_FORWARDER_PACKET_SIZE) { @@ -795,7 +795,7 @@ void TxFrame::dataSource( } } -void TxFrame::run(Rtl8812aDevice *rtlDevice, TxArgs *arg) { +void TxFrame::run(IRtlDevice *rtlDevice, TxArgs *arg) { // Decide if using VHT if (arg->bandwidth >= 80) { arg->vht_mode = true; diff --git a/app/wfbngrtl8812/src/main/cpp/TxFrame.h b/app/wfbngrtl8812/src/main/cpp/TxFrame.h index 72d37375..b37e3ab4 100644 --- a/app/wfbngrtl8812/src/main/cpp/TxFrame.h +++ b/app/wfbngrtl8812/src/main/cpp/TxFrame.h @@ -6,8 +6,8 @@ extern "C" { #include "wfb-ng/src/zfex.h" // FEC library } -#include "devourer/src/Rtl8812aDevice.h" // Rtl8812aDevice definition -#include "wfb-ng/src/wifibroadcast.hpp" // Wifibroadcast definitions +#include "devourer/src/IRtlDevice.h" // IRtlDevice interface (all chip generations) +#include "wfb-ng/src/wifibroadcast.hpp" // Wifibroadcast definitions // -- System / C++ Includes -- #include @@ -294,7 +294,7 @@ class UsbTransmitter : public Transmitter { uint8_t *radiotapHeader, size_t radiotapHeaderLen, uint8_t frameType, - Rtl8812aDevice *device); + IRtlDevice *device); ~UsbTransmitter() override = default; @@ -314,7 +314,7 @@ class UsbTransmitter : public Transmitter { uint8_t *radiotapHeader_; size_t radiotapHeaderLen_; uint8_t frameType_; - Rtl8812aDevice *rtlDevice_; + IRtlDevice *rtlDevice_; }; //------------------------------------------------------------- @@ -379,10 +379,10 @@ class TxFrame { /** * @brief Configures and runs the transmitter with the given arguments. - * @param rtlDevice The Rtl8812aDevice pointer (if using USB). + * @param rtlDevice The IRtlDevice pointer (if using USB). * @param arg TxArgs structure with user parameters. */ - void run(Rtl8812aDevice *rtlDevice, TxArgs *arg); + void run(IRtlDevice *rtlDevice, TxArgs *arg); /** * @brief Signals that the main loop should stop. diff --git a/app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp b/app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp index c7a364c7..217a9214 100644 --- a/app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp +++ b/app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp @@ -8,6 +8,7 @@ #include "RxFrame.h" #include "SignalQualityCalculator.h" #include "TxFrame.h" +#include "devourer/src/RxPacket.h" #include "libusb.h" #include "wfb-ng/src/wifibroadcast.hpp" @@ -56,7 +57,7 @@ std::string generate_random_string(size_t length) { WfbngLink::WfbngLink(JNIEnv *env, jobject context) : current_fd(-1), adaptive_link_enabled(true), adaptive_tx_power(30) { initAgg(); - Logger_t log; + log = std::make_shared(); // routes to logcat under the "devourer" tag wifi_driver = std::make_unique(log); } @@ -115,7 +116,16 @@ int WfbngLink::run(JNIEnv *env, jobject context, jint wifiChannel, jint bw, jint r = libusb_claim_interface(dev_handle, 0); __android_log_print(ANDROID_LOG_DEBUG, TAG, "Creating driver and device for fd=%d", fd); - rtl_devices.emplace(fd, wifi_driver->CreateRtlDevice(dev_handle)); + devourer::DeviceConfig cfg; + // TX+RX on the one claimed handle. Jaguar3 (RTL8812EU/8822EU) must know + // this before InitWrite so the bring-up keeps the RX filters open; + // Jaguar1 (RTL8812AU) ignores it. + cfg.rx.enable_with_tx = true; + // The per-adapter advisory lock defaults to /tmp, which doesn't exist on + // Android — use the app's files dir (same location as gs.key). + cfg.usb.lock_dir = "/data/user/0/com.openipc.pixelpilot/files"; + + rtl_devices[fd] = wifi_driver->CreateRtlDevice(dev_handle, ctx, nullptr, cfg); if (!rtl_devices.at(fd)) { libusb_exit(ctx); __android_log_print(ANDROID_LOG_ERROR, TAG, "CreateRtlDevice error"); @@ -185,22 +195,19 @@ int WfbngLink::run(JNIEnv *env, jobject context, jint wifiChannel, jint bw, jint // Store the current fd for later TX power updates. current_fd = fd; - if (!usb_event_thread) { - auto usb_event_thread_func = [ctx, this, fd] { - while (true) { - auto dev = this->rtl_devices.at(fd).get(); - if (dev == nullptr || dev->should_stop) break; - struct timeval timeout = {0, 500000}; // 500ms timeout - int r = libusb_handle_events_timeout(ctx, &timeout); - if (r < 0) { - this->log->error("Error handling events: {}", r); - // break; - } - } - }; + IRtlDevice *current_device = rtl_devices.at(fd).get(); - init_thread(usb_event_thread, [=]() { return std::make_unique(usb_event_thread_func); }); + // TX-capable bring-up with RX enabled (cfg.rx.enable_with_tx). On + // Jaguar3 (RTL8812EU/8822EU) this also starts the coex runtime thread + // that sustained TX needs. + auto bandWidth = (bw == 20 ? CHANNEL_WIDTH_20 : CHANNEL_WIDTH_40); + current_device->InitWrite(SelectedChannel{ + .Channel = static_cast(wifiChannel), + .ChannelOffset = 0, + .ChannelWidth = bandWidth, + }); + if (!usb_tx_thread) { std::shared_ptr args = std::make_shared(); args->udp_port = 8001; args->link_id = link_id; @@ -218,15 +225,12 @@ int WfbngLink::run(JNIEnv *env, jobject context, jint wifiChannel, jint bw, jint __android_log_print( ANDROID_LOG_ERROR, TAG, "radio link ID %d, radio PORT %d", args->link_id, args->radio_port); - Rtl8812aDevice *current_device = rtl_devices.at(fd).get(); - if (!usb_tx_thread) { - init_thread(usb_tx_thread, [&]() { - return std::make_unique([this, current_device, args] { - txFrame->run(current_device, args.get()); - __android_log_print(ANDROID_LOG_DEBUG, TAG, "usb_transfer thread should terminate"); - }); + init_thread(usb_tx_thread, [&]() { + return std::make_unique([this, current_device, args] { + txFrame->run(current_device, args.get()); + __android_log_print(ANDROID_LOG_DEBUG, TAG, "usb_transfer thread should terminate"); }); - } + }); if (adaptive_link_enabled) { stop_adaptive_link(); @@ -234,38 +238,37 @@ int WfbngLink::run(JNIEnv *env, jobject context, jint wifiChannel, jint bw, jint } } - auto bandWidth = (bw == 20 ? CHANNEL_WIDTH_20 : CHANNEL_WIDTH_40); - rtl_devices.at(fd)->Init(packetProcessor, - SelectedChannel{ - .Channel = static_cast(wifiChannel), - .ChannelOffset = 0, - .ChannelWidth = bandWidth, - }); + // Blocking RX loop on this thread; devourer pumps the libusb events + // itself. Returns once StopRxLoop() is called. + current_device->StartRxLoop(packetProcessor); } catch (const std::runtime_error &error) { __android_log_print(ANDROID_LOG_ERROR, TAG, "runtime_error: %s", error.what()); - auto dev = rtl_devices.at(fd).get(); - if (dev) { - dev->should_stop = true; - } txFrame->stop(); destroy_thread(usb_tx_thread); - destroy_thread(usb_event_thread); stop_adaptive_link(); + auto dev = rtl_devices.at(fd).get(); + if (dev) { + dev->Stop(); + } + libusb_release_interface(dev_handle, 0); + libusb_exit(ctx); return -1; } - __android_log_print(ANDROID_LOG_DEBUG, TAG, "Init done, releasing..."); - auto dev = rtl_devices.at(fd).get(); - if (dev) { - dev->should_stop = true; - } + __android_log_print(ANDROID_LOG_DEBUG, TAG, "RX loop exited, releasing..."); txFrame->stop(); destroy_thread(usb_tx_thread); - destroy_thread(usb_event_thread); stop_adaptive_link(); + // Clean shutdown: halt TRX DMA and power the chip down before releasing + // the USB interface. + auto dev = rtl_devices.at(fd).get(); + if (dev) { + dev->Stop(); + } + r = libusb_release_interface(dev_handle, 0); __android_log_print(ANDROID_LOG_DEBUG, TAG, "libusb_release_interface: %d", r); libusb_exit(ctx); @@ -280,7 +283,7 @@ void WfbngLink::stop(JNIEnv *env, jobject context, jint fd) { } auto dev = rtl_devices.at(fd).get(); if (dev) { - dev->should_stop = true; + dev->StopRxLoop(); } else { __android_log_print(ANDROID_LOG_ERROR, TAG, "rtl_devices.at(%d) is nullptr", fd); } diff --git a/app/wfbngrtl8812/src/main/cpp/WfbngLink.hpp b/app/wfbngrtl8812/src/main/cpp/WfbngLink.hpp index 195cce6e..24f74c5b 100644 --- a/app/wfbngrtl8812/src/main/cpp/WfbngLink.hpp +++ b/app/wfbngrtl8812/src/main/cpp/WfbngLink.hpp @@ -9,16 +9,20 @@ extern "C" { #include "wfb-ng/src/zfex.h" } +#include "devourer/src/IRtlDevice.h" #include "devourer/src/WiFiDriver.h" #include "wfb-ng/src/rx.hpp" +#include +#include #include #include #include #include +#include #include // Added for std::vector -const u8 wfb_tx_port = 160; -const u8 wfb_rx_port = 32; +const uint8_t wfb_tx_port = 160; +const uint8_t wfb_rx_port = 32; class WfbngLink { public: @@ -54,7 +58,7 @@ class WfbngLink { bool ldpc_enabled{true}; bool stbc_enabled{true}; - std::map> rtl_devices; + std::map> rtl_devices; std::unique_ptr link_quality_thread{nullptr}; bool should_clear_stats{false}; FecChangeController fec; @@ -87,7 +91,7 @@ class WfbngLink { if (rtl_devices.find(current_fd) == rtl_devices.end()) return; auto dev = rtl_devices.at(current_fd).get(); if (dev) { - dev->should_stop = true; + dev->StopRxLoop(); } } @@ -100,7 +104,6 @@ class WfbngLink { uint32_t udp_channel_id_be; Logger_t log; - std::unique_ptr usb_event_thread{nullptr}; std::unique_ptr usb_tx_thread{nullptr}; uint32_t link_id{7669206}; SignalQualityCalculator rssi_calculator; diff --git a/app/wfbngrtl8812/src/main/cpp/devourer b/app/wfbngrtl8812/src/main/cpp/devourer index bbc7385b..73f1cb4b 160000 --- a/app/wfbngrtl8812/src/main/cpp/devourer +++ b/app/wfbngrtl8812/src/main/cpp/devourer @@ -1 +1 @@ -Subproject commit bbc7385b9bce2098eab62ae37913a8879b994ef7 +Subproject commit 73f1cb4bcc6d1cfd6c5560f6637ce34aeaa94803