why is menu title not render properly on FR935?

i created this app to keep padel scores https://github.com/pedrorijo91/garmin-padel/

a user with Forerunner 935 is complaining the app does not work properly. According with him, these are the initial screens he gets:

initial screen (ok)

second screen (initial menu to select some options - where we see 'english' it should be 'Sets')

after selecting any option he gets this error:

I have no clue why screen 2 is not displaying menu properly. i suspect whatever the reason is leading to app to crash.

in the simulator everything seems fine:

1. any clue on what may be the issue? some API compatibility?

2. what's the best way to get more debug info for this and future cases?

  • There's some bug in the FW. So there's a chance the bug is in the code that reads the resource compiled from the xml and there it has something like:

    setTitle(language)

    instead of:

    setTitle(xmlMenu.title)

    So your idea of programmatically creating the menu is not bad IMHO

  • There's some bug in the FW. So there's a chance the bug is in the code that reads the resource compiled from the xml and there it has something like:

    setTitle(language)

    instead of:

    setTitle(xmlMenu.title)

    Yeah, that was my initial idea - after thinking about it for 5 minutes, I questioned it.

    I questioned to what extent the menu-building code is generated by the resource compiler as opposed to being in the device firmware. Sorry I did not make that abundantly clear.

    If all the menu-building code is actually generated by the resource compiler (which seems likely - why would Garmin waste code in the firmware to do something the compiler can do?), then it could also be that it's a bug in the old Menu class (which is used by the <menu> resource tag). And it could be that the reason I didn't see it on FR935 with my apps is because I used the newer Menu2 class.

    I tried the Menu SDK sample for fr935, which includes the following menu definition:

    <menu id="MainMenu" title="@Strings.MainMenuTitle" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://developer.garmin.com/downloads/connect-iq/resources.xsd">
        <menu-item id="Item1" label="@Strings.MenuLabel1"/>
        <menu-item id="Item2" label="@Strings.MenuLabel2"/>
    </menu>
    

  • Rez.mir (the generated intermediate representation for resources) has a MainMenu class corresponding to the MainMenu resource:

            [ @file = "...\ConnectIQ\Sdks\connectiq-sdk-win-8.1.0-2025-03-04-7ae1ed1cb\samples\MenuTest\bin\gen\006-B2691-00\source\Rez.mcgen"; @line = 34; @symbol_classdef = [MainMenu,34,14,22]; @symbol_extends<0> = [WatchUi,34,31,38]; @symbol_extends<1> = [Menu,34,39,43]; ]
            class MainMenu extends WatchUi.Menu {
                [ @file = "...\ConnectIQ\Sdks\connectiq-sdk-win-8.1.0-2025-03-04-7ae1ed1cb\samples\MenuTest\bin\gen\006-B2691-00\source\Rez.mcgen"; @line = 34; ]
                <init> {
                }
                [ @file = "...\ConnectIQ\Sdks\connectiq-sdk-win-8.1.0-2025-03-04-7ae1ed1cb\samples\MenuTest\bin\gen\006-B2691-00\source\Rez.mcgen"; @line = 34; ]
                static
                <init> {
                }
                [ @file = "...\ConnectIQ\Sdks\connectiq-sdk-win-8.1.0-2025-03-04-7ae1ed1cb\samples\MenuTest\bin\gen\006-B2691-00\source\Rez.mcgen"; @line = 35; @symbol_functiondef = [initialize,35,21,31]; ]
                function initialize() as Void {
    _ConnectIQ_Sdks_connectiq_sdk_win_8_1_0_2025_03_04_7ae1ed1cb_samples_MenuTest_bin_gen_006_B2691_00_source_Rez_mcgen_35_34_40_12_start:
    [ "...\ConnectIQ\Sdks\connectiq-sdk-win-8.1.0-2025-03-04-7ae1ed1cb\samples\MenuTest\bin\gen\006-B2691-00\source\Rez.mcgen" 36 16 ]
                    symbol [ Menu %tmp.2 36 16 20 ];
                    %tmp.2 = getv ? :Menu;
                    symbol [ initialize %tmp.3 36 21 31 ];
                    %tmp.3 = getv function %tmp.2 :initialize;
                    invoke %tmp.2 %tmp.3();
    [ "...\ConnectIQ\Sdks\connectiq-sdk-win-8.1.0-2025-03-04-7ae1ed1cb\samples\MenuTest\bin\gen\006-B2691-00\source\Rez.mcgen" 37 16 ]
                    symbol [ Menu %tmp.5 37 16 20 ];
                    %tmp.5 = getv ? :Menu;
                    symbol [ setTitle %tmp.6 37 21 29 ];
                    %tmp.6 = getv function %tmp.5 :setTitle;
                    symbol [ WatchUi %tmp.7 37 31 38 ];
                    %tmp.7 = getm $.Toybox.WatchUi;
                    symbol [ loadResource %tmp.8 37 39 51 ];
                    %tmp.8 = getv function %tmp.7 :loadResource;
                    symbol [ $ %tmp.9 37 52 53 ];
                    %tmp.9 = getm $;
                    symbol [ Rez %tmp.10 37 54 57 ];
                    %tmp.10 = getv %tmp.9 :Rez;
                    symbol [ Strings %tmp.11 37 58 65 ];
                    %tmp.11 = getv %tmp.10 :Strings;
                    symbol [ MainMenuTitle %tmp.12 37 66 79 ];
                    %tmp.12 = getv %tmp.11 :MainMenuTitle;
                    %tmp.13 = invoke %tmp.7 %tmp.8(%tmp.12);
                    %tmp.14 = as %tmp.13 String;
                    symbol [ String %tmp.14 37 84 90 ];
                    invoke %tmp.5 %tmp.6(%tmp.14);
    [ "...\ConnectIQ\Sdks\connectiq-sdk-win-8.1.0-2025-03-04-7ae1ed1cb\samples\MenuTest\bin\gen\006-B2691-00\source\Rez.mcgen" 38 16 ]
                    %tmp.15 = self;
                    symbol [ addItem %tmp.16 38 16 23 ];
                    %tmp.16 = getv function %tmp.15 :addItem;
                    symbol [ WatchUi %tmp.17 38 25 32 ];
                    %tmp.17 = getm $.Toybox.WatchUi;
                    symbol [ loadResource %tmp.18 38 33 45 ];
                    %tmp.18 = getv function %tmp.17 :loadResource;
                    symbol [ $ %tmp.19 38 46 47 ];
                    %tmp.19 = getm $;
                    symbol [ Rez %tmp.20 38 48 51 ];
                    %tmp.20 = getv %tmp.19 :Rez;
                    symbol [ Strings %tmp.21 38 52 59 ];
                    %tmp.21 = getv %tmp.20 :Strings;
                    symbol [ MenuLabel1 %tmp.22 38 60 70 ];
                    %tmp.22 = getv %tmp.21 :MenuLabel1;
                    %tmp.23 = invoke %tmp.17 %tmp.18(%tmp.22);
                    %tmp.24 = as %tmp.23 String;
                    symbol [ String %tmp.24 38 75 81 ];
                    %tmp.26 = const :Item1;
                    symbol [ Item1 %tmp.26 38 85 90 const ];
                    invoke %tmp.15 %tmp.16(%tmp.24, %tmp.26);
    [ "...\ConnectIQ\Sdks\connectiq-sdk-win-8.1.0-2025-03-04-7ae1ed1cb\samples\MenuTest\bin\gen\006-B2691-00\source\Rez.mcgen" 39 16 ]
                    %tmp.27 = self;
                    symbol [ addItem %tmp.28 39 16 23 ];
                    %tmp.28 = getv function %tmp.27 :addItem;
                    symbol [ WatchUi %tmp.29 39 25 32 ];
                    %tmp.29 = getm $.Toybox.WatchUi;
                    symbol [ loadResource %tmp.30 39 33 45 ];
                    %tmp.30 = getv function %tmp.29 :loadResource;
                    symbol [ $ %tmp.31 39 46 47 ];
                    %tmp.31 = getm $;
                    symbol [ Rez %tmp.32 39 48 51 ];
                    %tmp.32 = getv %tmp.31 :Rez;
                    symbol [ Strings %tmp.33 39 52 59 ];
                    %tmp.33 = getv %tmp.32 :Strings;
                    symbol [ MenuLabel2 %tmp.34 39 60 70 ];
                    %tmp.34 = getv %tmp.33 :MenuLabel2;
                    %tmp.35 = invoke %tmp.29 %tmp.30(%tmp.34);
                    %tmp.36 = as %tmp.35 String;
                    symbol [ String %tmp.36 39 75 81 ];
                    %tmp.38 = const :Item2;
                    symbol [ Item2 %tmp.38 39 85 90 const ];
                    invoke %tmp.27 %tmp.28(%tmp.36, %tmp.38);
    _ConnectIQ_Sdks_connectiq_sdk_win_8_1_0_2025_03_04_7ae1ed1cb_samples_MenuTest_bin_gen_006_B2691_00_source_Rez_mcgen_35_34_40_12_stop:
                }
            }
        

    Note how, after creating a new instance of the Menu class, the generated code grabs the title resource and calls setTitle. This mean there should be no difference (as far as the title goes) in creating Menu from a resource vs. creating it from code.

                    %tmp.5 = getv ? :Menu;
                    symbol [ setTitle %tmp.6 37 21 29 ];
                    %tmp.6 = getv function %tmp.5 :setTitle;
                    symbol [ WatchUi %tmp.7 37 31 38 ];
                    %tmp.7 = getm $.Toybox.WatchUi;
                    symbol [ loadResource %tmp.8 37 39 51 ];
                    %tmp.8 = getv function %tmp.7 :loadResource;
                    symbol [ $ %tmp.9 37 52 53 ];
                    %tmp.9 = getm $;
                    symbol [ Rez %tmp.10 37 54 57 ];
                    %tmp.10 = getv %tmp.9 :Rez;
                    symbol [ Strings %tmp.11 37 58 65 ];
                    %tmp.11 = getv %tmp.10 :Strings;
                    symbol [ MainMenuTitle %tmp.12 37 66 79 ];
                    %tmp.12 = getv %tmp.11 :MainMenuTitle;
                    %tmp.13 = invoke %tmp.7 %tmp.8(%tmp.12);
    

    Therefore, my conclusion is that it's likely an issue with the very old Menu class, and the workaround is probably to use the newer Menu2 class. Note that Menu2 can also be used from resources (the tag is <menu2>)

    Indeed, <menu> isn't barely mentioned in the Resources core topic docs now.

    https://developer.garmin.com/connect-iq/core-topics/resources/

    (there's still an old example of <menu> but the detailed docs refer to <menu2>)

  • TL;DR use the Menu2 class (<menu2> in resources) instead of Menu / <menu>.

    Menu2 is available starting with CIQ 3.0.0, including FR935 and all but the oldest devices (like anything released within the last 8 years)

    --

    NOTE: I tried the MenuTest SDK sample - which uses Menu from a <menu> resource - on a real FR935, and I saw the bug where the menu title was "English". I modded the source to create Menu programmatically, and as expected, the bug still occurs. Clearly the bug occurs whether Menu is created from a resource or programmatically.

    I am 100% sure Menu2 will work, as I still have an app of my own on my FR935 which uses Menu2 and does not have the bug.

    --

    (I upvoted my own comment for visibility, since this isn't a "question" where I can "suggest an answer")