"Unresolved symbols" when building external app that depends on infrared

Hi!

First of all: the Flipper Zero is a great tool and a very nice project!

As I’ve recently started playing around with the first LEGO Mindstorms generation, I found out that the IR interface with the yellow RCX programmable brick can be replayed with Flipper Zero.

I’ve been able to record and replay some signals, see:

I’d now like to play around with writing my own application (with a custom UI, not the one of the universam IR remotes) that runs on the Flipper Zero. In my understanding there are “plugins” and “applications”. I more or less only found two tutorials/ entry points for writing own apps. I am sure you can guide me to some other resources.

The first one: GitHub - DroomOne/Flipper-Plugin-Tutorial: Get started with Flipper Zero by building a Custom "Hello world" plugin (plugin)

The second one: GitHub - csBlueChip/FlipperZero_plugin_howto: A simple plugin for the FlipperZero written as a tutorial example [ie. excessive documentation & error handling]
The latter one also explains: ‘Since the move to FAP, your “plugins” are now known as “applications”’.

So, I’ve started to modify csBlueChip’s example as compiling my app as separate program seemed to be the right approach for me.

To get started, I’ve added some constant raw signals (the timings) in the code and added two calls so far:

const uint32_t aFwdTimings[] = {383, 409, 457, 376, 459, 373, 462, 371, 464, 785, 462, 4119, ..., 420, 1649, 413, 420, 1694, 375, 873};

...
	InfraredSignal* signal = infrared_signal_alloc();

	infrared_signal_set_raw_signal(
	            signal,
	            aFwdTimings,
	            sizeof(aFwdTimings)/sizeof(aFwdTimings[0]),
	            INFRARED_COMMON_CARRIER_FREQUENCY,
	            INFRARED_COMMON_DUTY_CYCLE);

Compling works fine after having added the relevant IR header files.
However, fbt_extapps.py seems to throw an error during build and indeed, the app cannot be loaded (or at least not be executed) successfully on the Flipper Zero:

	APPCHK	build/f7-firmware-D/.extapps/bc_demo.fap

fbt: warning: build/f7-firmware-D/.extapps/bc_demo.fap: app won't run. Unresolved symbols: {'infrared_signal_alloc', 'infrared_signal_set_raw_signal'}
validate_app_imports, line 204, in file "/somefolder/flipperZero/official/scripts/fbt_tools/fbt_extapps.py"

I’ve tried to add infrared to the fap_libs and requires entries in the .fam file, but that does not seem to do the trick:

# qv. https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppManifests.md

App(
    appid="bc_demo",
    apptype=FlipperAppType.EXTERNAL,
    name="RCX Remote",
    entry_point="bc_demo",
    cdefines=["APP_BC_DEMO"],
    fap_libs=["infrared"],
    requires=[
        "gui",
        "infrared"
    ],
    stack_size=2 * 1024,
    order=20,
    fap_icon="CS.png",
    fap_category="maehw tests",
)

Any hint is very welcome.

Edit: I am not sure if I am on the right path… I’d call infrared_tx_start_signal which itself needs a pointer to an Infrared instance, which other code casts from the “context”. How could I get an IR instance (or a pointer to one) from the app’s code?

It seems that you are trying to use the insides of the built-in Infrared application, which are not exported as the public API available in FAPs.
That said, the only functions and variables that are available for use in the FAPs are those listed in firmware/targets/f7/api_symbols.csv.
The quickest solution would be copying the necessary code from the Infrared application to yours.
It is possible, however, to identify the potentially reusable code and move it to 'lib/infrared` so that it becomes outside the Infrared application (and submitting a pull request so that everyone could benefit from that).

1 Like

Thank you for your help @gsurkov !

I am now able to build and load the app on my Flipper Zero ready for execution.

Now begins the hard part. Understanding why things don’t work.

I’ve put the following lines in my application’s entry point:

	infrared = malloc(sizeof(Infrared));
	furi_assert(infrared);

	infrared->worker = infrared_worker_alloc();
	furi_assert(infrared->worker);

	infrared_worker_set_raw_signal(infrared->worker, aFwdTimings, sizeof(aFwdTimings)/sizeof(aFwdTimings[0]));

	infrared_worker_tx_set_get_signal_callback(
	        infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);

plus

the run loop

plus

  infrared_worker_free(infrared->worker);
  free(infrared);

Inside the run loop (almost unmodified bc_demo example), key events are processed within evKey.

	switch (msg->input.type) {
		case InputTypeShort:   // Short   - after InputTypeRelease within INPUT_LONG_PRESS interval
			if (msg->input.key == InputKeyOk)
			{
			  animateEn(state, !state->animate) ;
				furi_assert(infrared);
				furi_assert(infrared->worker);
				infrared_worker_tx_start(infrared->worker);
			}
			break;

The second short key press lights up the LED in blue and then crashes my app - but I don’t think at the location where I’ve inserted good. Could someone please guide me the next step - how to debug applications?

Edit: Replacing the infrared_worker_tx_start call by

					infrared_worker_tx_stop(infrared->worker);
					infrared_worker_tx_start(infrared->worker);

does not make the app crash on button press but only on exit of the app.