betaflight / betaflight-configurator

Cross platform configuration tool for the Betaflight firmware
GNU General Public License v3.0
2.54k stars 899 forks source link

Flight controllers requiring CP2104 driver not working in android #2437

Closed danybd closed 3 years ago

danybd commented 3 years ago

I´ve installed betaflight configurator in a android device and tried to connect to a FC with an USB UART built-in. I did the same test for 3 different flight controller. Two of them (SPracingF3 and Naze32) with Sil2104 ICs and one with I believe native usb support (CrazyBeeF3). The last one is working properly, the first ones dont. When I try to connect to the FCs I got a popup message "do you want to allow Betaflight Configurator access to CP2104 USB to UART Bridge Controller?" and two buttons below "cancel" / "accept". After clickling on accept the tool crashes and get closed by android task manager. Is these "legacy" hardware not supported or is it just a bug? I´ve got android 10 and betaflight configurator 10.7.0

haslinghuis commented 3 years ago

Don't have the hardware to confirm and can't find the message in configurator source. I guess it's an issue with Android not having a driver implementation for Silabs CP210x.

danybd commented 3 years ago

I´ll try to do some research to find out, what is exactly crashing. There should be some kind of logging register in android where events get logged.

McGiverGim commented 3 years ago

This two FC are not maintained anymore, are very old (specially the Naze32). So we can't be sure that the current configurator will work with them. I suppose you have tried both in a computer, so if they work there, it must work in Android if you can find the problem with the driver.

McGiverGim commented 3 years ago

Maybe we need to change this filtering:

https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/cordova/usb_device_filter.xml#L1-L4

To accept other USB definitions?

McGiverGim commented 3 years ago

At least I suppose we need to support the same than we do in other SO:

https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/port_handler.js#L5-L8

danybd commented 3 years ago

@McGiverGim yes, I tried on the computer and there is working perfect. But in android prints the message "Failed to open serial port". I discard driver issue as other serial terminal tool are working and establishing connection with the FC. I installed yesterday the last nightly build and right now I´ve got installed 10.8.0 In the tab where ports are listed shows vendorId and productId in decimal as "4292/60000 - 4292/60000" I could try a build with the suggested changes by @McGiverGim

danybd commented 3 years ago

My android devices is detecting the FC as: vendorId: 10C4 productId: EA60

danybd commented 3 years ago

Progress update: I checked out the repository and prepared my system so that I was able to build an .apk including the mod suggested by @McGiverGim. Unfortunately it did not work and I am still not able to connect with the FC. If you have any idea I can keep trying possible fixes.

danybd commented 3 years ago

Well I did some "progress" at debugging. I looks like that in serial_backend.js the callback function onOpen(openInfo) { if (openInfo) { ... is getting false as input parameter (which actually is the ConnectionInfo). This callback is called in serial.connect(portName, {bitrate: selected_baud}, onOpen); and as I read in the documentation, the callback gets only called if the port could be opened successfully.

serial.connect(path, options, callback) path (string): If the path associated with your device's port is unknown, you can use the serial.getDevices method options (object): Parameter object with several configuration values. See details at serial.ConnectionOptions callback: Invoked when the port has been successfully opened. The callback will be called with one parameter, connectionInfo, that has several important values. See details at serial.ConnectionInfo.

I do not really understand why ConnectionInfo is false if the port was apparently open successfully. Hopefully somebody knows, what is going on. For me is the first time I have a look into .js

haslinghuis commented 3 years ago

It's part of the chrome API we are using. But still not sure 2104 is included in Android. https://www.silabs.com/documents/public/application-notes/AN809.pdf

McGiverGim commented 3 years ago

Maybe @WalcoFPV can help here, is the one with more knowledge about Android...

WalcoFPV commented 3 years ago

I think, there are 2 possible issues. The first one, which propably causes crashes of the app, is that the preview build of the Android app uses a very old version of an android library called usb-serial-for-android. This issue is fixed in master so using a nightly build can solve this issue. The second one is that, on Android, the configurator, will only allow connection to devices listed in /cordova/usb_device_filter.xml. So adding the vendorId and productId of the CP2104 USB to UART Bridge Controller could solve the issue.

The serial chrome API doesn't exist on Android (more precisely for Cordova). So I had to "simulate it" with existing Cordova plugins as cordovarduino (which is a bridge between the Configurator and the native Android library usb-serial-for-android). So it is possible that some information that the serial Chrome API is supposed to return, is not correctly returned on Android. You can take a look at /src/js/cordova_chromeapi.js

danybd commented 3 years ago

@WalcoFPV the crash problem was happening with 10.7.0. This issue does not happen with nightly 10.8.0 Regarding /cordova/usb_device_filter.xml I did yesterday the change and build an .apk but it did not help. In log area pop-up the message "Failed to open serial port". I will have a look into the suggested modules. Any advice for online debugging (with breakpoints on target)?

WalcoFPV commented 3 years ago

I think, I found something. It seems the vendorId and the productId of the CP2104 USB to UART Bridge Controller contain letters. But during the connection, the configurator converts them to int. https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_chromeapi.js#L158-L159

@danybd I don't know how to debug online. Debugging the app with usb is annoying : having to plug in the flight controller and then plug in the usb to debug the app ... but I don't know other solutions.

danybd commented 3 years ago

@WalcoFPV I readout the vendorId and productId in my android device using a tool from Play Store: vendorId: 10C4 productId: EA60 I assumed these are hex numbers. The same conversion is taking place FC like CrayzBee (STM32F3) and there is no issue at all

danybd commented 3 years ago

I´m confused. Is the module serial.js being used in the android app? Is replaced by cordova_chromeapi.js? Both of them have serial routines implemented. What I observed is that the callback onOpen(openInfo) gets false as input parameter (openInfo=false) https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/serial_backend.js#L220-L224 Looking in serial.js found the function connect and connectSerial https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/serial.js#L18-L34 The function connectSerial is calling the callback onOpen with false https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/serial.js#L137-L143

WalcoFPV commented 3 years ago

@danybd yes serial.js is used. All the configurator uses the serial chrome API. But, on Android, we use Cordova which doesn't provide this api. So, cordova_chromeapi.js creates the serial Chrome API methods with a Cordova plugin cordovarduino which uses the usb-serial-for-android native Android library.

So, I am almost sure the issue come from cordova_chromeapi.js, the cordovarduino Cordova plugin or the usb-serial-for-android native Android library doesn't work for this serial controller.

danybd commented 3 years ago

There is definitely a ChromeRuntimeError at this point: https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/serial.js#L34

danybd commented 3 years ago

I am really having hard to follow the .js execution flow. @WalcoFPV how do you come from https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/serial.js#L33 to https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_chromeapi.js#L151 I don't see the connection. I´m Python and C/C++ guy. First time for me looking .js. I don´t see any "imports" or something similar to understand where are functions called from. I´ve been investigating cordovarduino and usb-serial-for-android and both claim to support cp210x devices.

WalcoFPV commented 3 years ago

@danybd In cordova_chromeapi.js, an object chromeapiSerial is defined. This object contains the same methods than chrome.serial but for Cordova. https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_chromeapi.js#L47-L250 Because chrome.serial is not natively available on Cordova, during the initialization of Cordova, chrome.serial = chromeapiSerial is set. https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_chromeapi.js#L398-L406 https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_startup.js#L51-L67 So, when the configurator runs on Android, chrome.serial.connect in serial.js calls chromeapiSerial.connect in cordova_chromeapi.js

WalcoFPV commented 3 years ago

@danybd

There is definitely a ChromeRuntimeError at this point: https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/serial.js#L34

When running on Android, a ChromeRuntimeError can be also set in cordova_chromeapi.js https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_chromeapi.js#L3-L35

But, I think, we don't take the right approach. With the flight controller wired to your phone, what is the name of the port of the fc shown by the configurator ?

danybd commented 3 years ago

@WalcoFPV

But, I think, we don't take the right approach. With the flight controller wired to your phone, what is the name of the port of the fc shown by the configurator ?

It is showing 4292/60000 - 4292/60000 which is the decimal vendorId and productId

danybd commented 3 years ago

Thank you for the explanations! What I still do not understand is how .js "knows" that this https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_chromeapi.js#L398-L406 and this: https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/serial.js#L33 are related. I could more or less follow the flow execution because you said me "look there". I would never find out looking in the code that cordova_chromeapi.js overloads chrome.serial and serial.js "references" cordova_chromeapi.js. Is this relatiship defined in some kind of build file outside src? I look how modules are imported in .js and keywords like export and require are needed.

haslinghuis commented 3 years ago

@danybd look again: chromeapiSerial is assigned to chrome.serial and as such you should read chrome.serial.connect() as chromeapiSerial.connect(); but connect is defined in cordova_chromeapi.js, so I guess it doesn't use the one in serial.js. Also getDevices is redefined for Android in the same file to build the list of devices attached to USB.

On https://github.com/xseignard/cordovarduino#your-device-is-not-yet-known there is shown how to attach the right driver to the device vid/pid (usbDevices in port_handler.js but it could just be using devices in cordova_chromeapi.js), so I'm not sure where to assign .

danybd commented 3 years ago

@haslinghuis

connect is defined in cordova_chromeapi.js, so I guess it doesn't use the one in serial.js.

I found the issue #2433 which explains why I am having hard time understanding the code 😄

Yes, it do. Because in serial.js the code in connect is actually a callback function, which is called by chrome.serial.connect() from cordova_chromeapi.js Is there any possibility to see the console.log() messages? Currently I am debugging inserting GUI.log() in the code and building the .apk, but this is extremely inefficient and time consuming (build time +/- 3min). How do you do it? Do you use an emulator? The driver library usb-serial-for-android says:

Compatible Devices This library supports USB to serial converter chips: FTDI FT232R, FT232H, FT2232H, FT4232H, FT230X, FT231X, FT234XD Prolific PL2303 Silabs CP2102 and all other CP210x Qinheng CH340, CH341A

So I guess the CP2104 should be supported.

danybd commented 3 years ago

Debugging update: I found out another point where the execution is going wrong: https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_chromeapi.js#L163-L175 At this point the chromeCallbackWithError(self.logHeader+error, callback); is called. I modified the code and insert a debug instruction and built the .apk.

GUI.log("chromeCallbackWithError: " + self.logHeader+error); chromeCallbackWithError(self.logHeader+error, callback);

After doing that I found out what is the value of self.logHeader+error => "SERIAL (adapted from Cordova): No control endpoint" It looks like the problem is in cordova_serial...

danybd commented 3 years ago

I´ve found the bug!!! 🥳 The problem was a wrong driver selection. The function cordova_serial.requestPermission takes an optional parameter driver. If no driver parameter is provided then it uses the default one CdcAcmSerialDriver which is not working for the FC with CP2104 USB-UART chip. The bugfix is pretty straightforward. Instead: https://github.com/betaflight/betaflight-configurator/blob/9cedeb23ca7f8c26874eb9556d0ad7d3819c521f/src/js/cordova_chromeapi.js#L161 we have to differentiate the driver depending on the board cordova_serial.requestPermission({vid: vid, pid: pid, driver: "Cp21xxSerialDriver | CdcAcmSerialDriver"}. I´ll do today a pull request with the bugfix. Thank you all for the advices.

McGiverGim commented 3 years ago

Is better not to close the issue, and link the PR to it. It will be closed when the PR is merged.

danybd commented 3 years ago

Is better not to close the issue, and link the PR to it. It will be closed when the PR is merged.

@McGiverGim Ok, I reopen the issue. It is my first PR so, I don't really know the workflow. I already did the PR.

danybd commented 3 years ago

@McGiverGim should this issue be labeled as bug? I am not able to do that, right?

McGiverGim commented 3 years ago

Yes, I will add it.

EricKosowsky commented 1 year ago

So what do we need to do so we can get past it and connect to BF? I haven't flown in 2 months because of the stupid Cordova bullshit