flipperzero icon indicating copy to clipboard operation
flipperzero copied to clipboard

USB and Bluetooth Remote controller example

Open ASoldo opened this issue 1 year ago • 9 comments

Hi, I would like to make simple USB/Bluetooth Remote controller (HID - Keyboard) with few screens (like elgato stream deck). Is there any example of how to make Rust version of Remote keyboard app from FlipperZero? All I actually need is sample of how to use USB/Bluetooth to send keys like keyboard button press when user selects one option and clicks ok.

ASoldo avatar Mar 18 '24 06:03 ASoldo

Hi @ASoldo,

At this point we don't have an example of using Bluetooth or USB from the Rust bindings, but it should be possible via the low-level flipperzero-sys crate.

Typically my approach has been to find the equivalent app in the Flipper Zero firmware (the HID app looks like the right one) and then port that across more or less verbatim.

I try not to make any high-level Rust bindings until I have a good understanding of how the C-API works, otherwise it limits what you would be able to do with it.

dcoles avatar Mar 18 '24 18:03 dcoles

I see, yes. I am now trying out the USB remote keyboard app in C to see how it's made, but in general, that's the app I wanna create but modify for my needs. I am still learning FZ and Rust, but once I figure out how it works, I should be able to call the same functions, but from flipperzero-sys crate?

ASoldo avatar Mar 18 '24 19:03 ASoldo

Yes. That's right. The gpio and gui examples are good ones that show what working directly with the flipperzero-sys crate is like.

If you get stuck, I or one of the other maintainers can give you some pointers in the right direction.

dcoles avatar Mar 18 '24 19:03 dcoles

After reading C code and then compared to Rust code I don't see furi_check() anywhere, why is that? All other methods are on sys crate. Do I need it when working with fz-rs or is it just for C?

ASoldo avatar Mar 20 '24 00:03 ASoldo

@ASoldo the purpose of furi_check is to assert some invariant. This is mostly used as a fail-safe mechanism in Flipperzero Firmware.

For example, it is much better to just instantly exit with an error on a null pointer received (where not expected) rather than to continue execution and face undefined behaviour.

In the case of writing an app on Rust, there are multiple answers to this question:

  1. Generally speaking, if you are sure :tm: that some invariant is upheld, then you may be fine not checking it.
  2. Whenever you are not sure, it may be worth adding an extra check for this. This will cause a check overhead but you will have a more deterministic behavior. For this purpose Rust's assert*! and debug_assert*! macros may be your friends (we delegate to Furi stuff on panic's so it should be fined to use them).
  3. Ideally though, in Rust you would try to create a safe wrapper structure which would internally uphold the invariants, while externally always be safe to use (sound). A good example of such an abstraction is a Vec from alloc: while externally it is just a raw pointer and two sizes (length and capacity), its external interface allows you to make all kinds of safe operations without checking for these things. For this I suggest that you look at how some wrappers are currently implemented for Furi components in flipperzero, for example the MessageQueue.

Good luck with your project!

JarvisCraft avatar Mar 20 '24 02:03 JarvisCraft

Just to add a little more context (@JarvisCraft beat me to the reply):

The reason that there's no furi_check is because it is a macro, which bindgen isn't able to translate.

The equivalent would be the Rust core::assert! macro. If the expression fails, then Rust will call the system panic handler that prints a message to the Furi console then crashes the system in the same way that furi_check does.

dcoles avatar Mar 20 '24 03:03 dcoles

I see, now it makes more sense. I just got the feel for sys crate and how to work with it (translate C code to Rust) and was confused why i can't find it in any crate.

ASoldo avatar Mar 20 '24 05:03 ASoldo

I've started writing Rust bindings for the Bluetooth APIs in #139. Currently I have APIs for the beacon and the test pattern generators; next will probably be an initial version of an API for Bluetooth HID.

str4d avatar Apr 02 '24 01:04 str4d

That sounds great. I'd like to try it when it's ready.

ASoldo avatar Apr 02 '24 01:04 ASoldo