Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/`
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/xml/usb_device_filter.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,13 @@
<usb-device
product-id="3426"
vendor-id="0586" /> <!-- ZyXel 6605 -->
<usb-device
product-id="A81A"
vendor-id="0BDA" /> <!-- RTL8812EU (e.g. LB-LINK BL-M8812EU2) -->
<usb-device
product-id="A82A"
vendor-id="0BDA" /> <!-- RTL8822EU -->
<usb-device
product-id="E822"
vendor-id="0BDA" /> <!-- RTL8822EU (multi-function) -->
</resources>
90 changes: 58 additions & 32 deletions app/wfbngrtl8812/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions app/wfbngrtl8812/src/main/cpp/TxFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions app/wfbngrtl8812/src/main/cpp/TxFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <algorithm>
Expand Down Expand Up @@ -294,7 +294,7 @@ class UsbTransmitter : public Transmitter {
uint8_t *radiotapHeader,
size_t radiotapHeaderLen,
uint8_t frameType,
Rtl8812aDevice *device);
IRtlDevice *device);

~UsbTransmitter() override = default;

Expand All @@ -314,7 +314,7 @@ class UsbTransmitter : public Transmitter {
uint8_t *radiotapHeader_;
size_t radiotapHeaderLen_;
uint8_t frameType_;
Rtl8812aDevice *rtlDevice_;
IRtlDevice *rtlDevice_;
};

//-------------------------------------------------------------
Expand Down Expand Up @@ -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.
Expand Down
89 changes: 46 additions & 43 deletions app/wfbngrtl8812/src/main/cpp/WfbngLink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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<Logger>(); // routes to logcat under the "devourer" tag
wifi_driver = std::make_unique<WiFiDriver>(log);
}

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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<std::thread>(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<uint8_t>(wifiChannel),
.ChannelOffset = 0,
.ChannelWidth = bandWidth,
});

if (!usb_tx_thread) {
std::shared_ptr<TxArgs> args = std::make_shared<TxArgs>();
args->udp_port = 8001;
args->link_id = link_id;
Expand All @@ -218,54 +225,50 @@ 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<std::thread>([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<std::thread>([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();
start_link_quality_thread(fd);
}
}

auto bandWidth = (bw == 20 ? CHANNEL_WIDTH_20 : CHANNEL_WIDTH_40);
rtl_devices.at(fd)->Init(packetProcessor,
SelectedChannel{
.Channel = static_cast<uint8_t>(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);
Expand All @@ -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);
}
Expand Down
Loading