Order of initialisation for Lua code blocks

Hi, using the most recent firmware (I’ve not updated for a while!) i’ve started having issues with my lua code. Because of the (incredibly annoying) code block size limits i’ve had to split my code up across the setup pages of the various elements, as well as the general block setup page. In the past this worked, but now when I initialize the block I get issues about code not being callable. If I go in and edit the code and save it works again, but then when I disconnect and reconnect I get errors, so it must be to do with order of initialisation. What is the correct way to structure a complex program to make it work? In what order should the functions be added to the elements so that everything can see everything else?

I have to say that the most annoying part of these controllers is the code block size limits, they make setting up anything complex way more difficult than it needs to be, and the size restrictions seem so arbitrary, it would be really nice to have an option which just imposed a global code size limit that you could use across all the elements, so I could put all of my program code inside the block setup, and then just call it with a line or two from the elements themselves, it would make it much better in terms of reasoning about your program as well.

Hi!

So the setup events work in this order:
1. The Setup event of the System initializes.
2. Then in ascending order by index# all of the Setup events follow on every other control element.

So for example on an EF44,
1. System Setup
2. 0-3 Encoder Setups
3. 4-7 Fader Setups

And after that code only runs on event triggers unrelated to intialization.
Hope this helps explain how it works.

Edited on July 10th of 2025:
The above explanation is outdated above FW version 1.3.6, see my comment below for a workaround if your configuration seems broken.

Hi,

Thanks very much for the explanation. I actually assumed that’s how it was ordered and structured my code as such, and as mentioned it worked in previous versions, but its not working now despite my not making any changes other than updating the firmware. I’ve attached my broken config as maybe that can help you find the issue. It’s for a PO16. Since I can’t attach a file I’ve had to paste in the json

{
    "id": "0912a442-9376-4a6b-af11-c3dce4ad0896",
    "modifiedAt": "2025-07-08T16:21:57.760Z",
    "name": "BrokenConfig",
    "description": "Click here to add description",
    "type": "PO16",
    "version": {
        "major": "1",
        "minor": "5",
        "patch": "8-nightly"
    },
    "configType": "profile",
    "configs": [
        {
            "controlElementNumber": 0,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu,cc=self:ind(),self:pva(),221,143,255,37--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)--[[@cb]] function sendCCDataOut(num,cc,val)gms(FP-1,176,cc,val)lvals[FP][num]=val;if deadzone(val)then glp(num,1,0)else glp(num,1,val)end end"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),37--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 1,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),98,0,255--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)--[[@cb]] function isWithinRange(a,b,x)return(a>=b-x)and(a<=b+x)end;function deadzone(val)return isWithinRangeOfArray(val,INDCBNDS,3)end"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),38--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 2,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),255,255,255--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)--[[@cb]] function has_value(tab,val)for index,value in ipairs(tab)do if value==val then return true end end;return false end"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),39--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 3,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,r,g,b=self:ind(),self:pva(),255,255,0--[[@glc]] glc(num,1,255,242,0,0)--[[@glp]] glp(num,1,val)--[[@cb]] function lset()for i=0,gec()-2 do if isWithinRange(ele[i]:pva(),lvals[FP][i],3)then locked[i]=0;glf(i,1,0)glp(i,1,lvals[FP][i])else locked[i]=1;glf(i,1,255)end end end;for i=0,gec()-2 do lvals[1][i]=ele[i]:pva()lvals[2][i]=0 end"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),40--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 4,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),221,143,255--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),41--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 5,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),30,255,0--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),42--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 6,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),98,0,255--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),43--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 7,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,r,g,b=self:ind(),self:pva(),98,0,255--[[@glc]] glc(num,1,r,g,b,0)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),44--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 8,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),221,143,255--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),45--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 9,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),30,255,0--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),46--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 10,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),98,0,255--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),47--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 11,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,r,g,b=self:ind(),self:pva(),98,0,255--[[@glc]] glc(num,1,r,g,b,0)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),48--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 12,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),221,143,255--[[@glc]] glc(num,1,221,143,255,0)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),49--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 13,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,r,g,b=self:ind(),self:pva(),30,255,0--[[@glc]] glc(num,1,r,g,b,0)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),50--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 14,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,red,gre,blu=self:ind(),self:pva(),98,0,255--[[@glc]] glc(num,1,red,gre,blu)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),51--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 15,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@l]] local num,val,r,g,b=self:ind(),self:pva(),98,0,255--[[@glc]] glc(num,1,r,g,b,0)--[[@glp]] glp(num,1,val)"
                },
                {
                    "event": 1,
                    "config": "--[[@l]] local num,val,cc=self:ind(),self:pva(),52--[[@cb]] if locked[num]==1 then if isWithinRange(val,lvals[FP][num],3)then locked[num]=0;glf(num,1,0)sendCCDataOut(num,cc,val)end else sendCCDataOut(num,cc,val)end"
                },
                {
                    "event": 6,
                    "config": "--[[@cb]] print('tick')"
                }
            ]
        },
        {
            "controlElementNumber": 255,
            "events": [
                {
                    "event": 0,
                    "config": "--[[@cb]] lvals={{[0]=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},{[0]=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}locked={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}FP=1;function cFP(p)FP=p;lset()end;INDCBNDS={32,64,96}function isWithinRangeOfArray(value,array,range)for _,item in ipairs(array)do if value>=(item-range)and value<=(item+range)then return true end end;return false end"
                },
                {
                    "event": 4,
                    "config": "--[[@cb]] gpl(gpn())"
                },
                {
                    "event": 5,
                    "config": "--[[@l]] local ch,cmd,param1,param2=midi.ch,midi.cmd,midi.p1,midi.p2"
                },
                {
                    "event": 6,
                    "config": ""
                }
            ]
        }
    ],
    "createdAt": "2025-07-08T16:21:57.760Z",
    "cloudId": "IGVGzxXglEGOU7EgXLKY",
    "owner": "s7dYOXFQRKb0HLB9W2injuKdjNF2"
}

As far as I can tell, the debug messages say that you do not have the “deadzone” variable initialized.

Can’t find anything else wrong with the config, but that doesn’t allow it to work, as “deadzone” should be some kind of global variable you forgot to (?) initialize.

deadzone is a function defined on element one of the controller, you can see it in the config above at controlElementNumber": 1, event 0

Oh that’s true. Sorry about that.

I found the culprit though. Here’s the quick solution: put the following piece of code under System Setup:

for i = 0, #element - 1 do
    element[i]:ini()
end

The long answer is that you were right. The initialization order has been changed, and I didn’t realize how much this will influence.
Since the latest release FW the order changed to the following:

  1. System Setup
  2. System other Events
  3. Element 0 Setup
  4. Element 0 other Events
  5. Element 1 Setup
  6. Element 1 other Events

and so on…

The problem with the above is that you (and most everyone that makes configs for Grid) distributes their function initializations all over the Setup Events of the module. But if you also call the incomplete function on the first element, the whole initialization process breaks.

So for now the solution is to pre-trigger all Setup events after System Setup runs. It’s ugly but it works.

Very luck that it’s just enough characters to be under the limit for me :sweat_smile: Thanks for providing a work around for this.

It really does make me wish that the code size limits on each section were less arbitrary though, because my preference would always to be to put the bulk of my program on the system setup block, and use minimal calls to it from each element. I would imagine most people feel the same, since it’s much easier to reason about your program if all the code is kept in one place. If that were possible I would have never even have encountered this issue!

1 Like

Is this still a concern for the latest firmwire? I’ve been experimenting with calling ini() explicitly as suggested by @narayb above, and I’m getting some very strange results: sometimes it works, sometimes it does not with Lua complaining that ini is not defined. I am not sure where this non-determinism is coming from; I also have the impression that clicking “store” to update the device is not always reliable, and if I clear everything first and then switch back things are better. But it’s very hard to be sure.

I very much agree with @t_whiston that this character limitation is very frustrating. It would have been far preferable to have a large character limit on the system setup so that I can put a ton of code there, and then much less for the other action chains. As it stands, making sure that this initialization happens correctly I’ve found to be quite difficult so far.

Long answer

It still should be the case, yes. We haven’t changed how Setup order works since and I’m not aware of bugs relating to initialization order. At least not on the latest release firmware version (nightly is another matter entirely).

There is work going on behind the scenes to get rid of this in the near future, so it becomes less of a hassle and you can see some of this on the nightly firmware already. We’re going to open up the actual initialization LUA file for the userspace and you’ll be able to init and require LUA there as you need and the usual Setup/Element Events will be ran after that if you so desire.
This is a WIP, looking at releasing it this summer. Feature-set will include file-system editing during runtime, LUA file loading from Editor and more.
It should also somewhat alleviate the issues that arise from the character limit, since you’ll be able to require libraries at initialization from persistent storage and they don’t have to live in the configuration proper. This expands Grids configuration potential quite a bit, the next bottleneck we’re now running into is RAM, so if your current configs don’t really cross over the 120k limit, you should be much better off in the future while scripting for Grid.

The initiative is to allow power users into a much more familiar territory where they can write code in a code editor to create a library and later use it on Grid and even potentially share it with others.

Regarding the issues you’re describing on current firmware:

  • Is this inconsistency with the Store function relegated to a specific profile you’re using? If so, please share it and I can take a look and see what could be going wrong.
  • As I tried to expand on above as well, character limits will be a less of a thing in the future as we will open up a workflow where you can call libraries from file that don’t have to be written into the configuration and this way the only space your configuration will have to use from the char limit will be the functions directly related to the Elements. This should help a lot by freeing up code space in the configuration itself.

Small conclusions

  1. Yes, init is still weird in the current release firmware, so what I wrote about init order still applies today.
  2. We are changing how Grid users can interact with Initialization in the near future, so initializing functions in Setup Events and worrying about code limit will hopefully be a thing of the past.
1 Like

Oh wow, yes, that sounds fantastic! That sounds like it will be a much better experience, at least for people such as myself who are programmers; I very much look forward to that!

When I have a semi reliable way to reproduce the problems I mentioned I will let you know, but of course the nature of non-deterministic problems makes that challenging :slight_smile: I will keep a close eye as I develop my project further.

Thanks for the reply :slight_smile:

1 Like