Home AMX User Forum AMXForums Archive Threads Tips and Tricks

Known (or apparent) bugs - post yours here

Try looking at this code in Netlinx Studio 2.

The editor (but not the compiler) seems to regard /* as the beginning of a comment in this context. /* */ are apparently treated the same as (* *) so you can see how that might happen.

(*
hello //*
*)
This is not a comment but the compiler thinks it is
«1

Comments

  • Master compiles despite module compile failure

    When a module fails to compile with almost any error, the master program won't compile because the module.tko is missing. But when the error is eg

    "[2] arguments for function...taking [3] arguments"

    the master program compiles because the .tko does exist somehow.

    The moral of the story is to check the compiler error message count, don't just check that the master file compiled.
  • Constant defined with expression gets it wrong

    The NS2 help text clearly indicates that you may define the value of a constant or the initial value of a variable using an arithmetic expression on the RHS, and the compiler happily does it, but it turns out that it gets it badly wrong in some circumstances.

    This program illustrates what happens; everything acquires the value 88 instead of 600.

    program_name='Oops'

    define_constant

    nOneMinuteTenths = 10 * 60
    integer nOneMinuteTenthsInteger = 10 * 60

    define_variable

    vnOneMinuteTenths = 10 * 60
    integer vnOneMinuteTenthsInteger = 10 * 60

    define_program

    wait 100
    {
    send_string 0,"'nOneMinuteTenths=' ,itoa(nOneMinuteTenths)"
    send_string 0,"'nOneMinuteTenthsInteger=' ,itoa(nOneMinuteTenthsInteger)"
    send_string 0,"'vnOneMinuteTenths=' ,itoa(vnOneMinuteTenths)"
    send_string 0,"'vnOneMinuteTenthsInteger=' ,itoa(vnOneMinuteTenthsInteger)"
    }

    It appears that when all of the literals on the RHS (10, 60) are small enough for a char the result becomes a char (600 modulo 256 is 88) even when you define the constant as an integer.

    The workaround is never to use an expression to initialise a constant, it will sometimes work, and sometimes not.

    For clarity, consider this:

    integer nOneMinuteTenths = 600 (* 10 * 60 *)
  • Debug can't handle the same variable in different modules

    If you try to debug a variable that appears with the same name in more than one module, there is no way of knowing which one you are selecting, and thereafter looking at, and if you look at the same variable in more than one module, you appear to see multiple copies of whichever one you nominated last.
  • Modal popup suppresses the release of the button that opened it

    If the push of a touchpanel button causes the code to open a modal popup, the release of that button is never seen, which means that the next push on that button is also not seen, and you have to push it twice.

    The best workaround is to open the popup on the release, not the push, which was someone else's idea - so I won't take the credit.
  • NS2 compiler allows array bounds to be set with variables

    The NS2 NetLinx compiler will let you define an array variable using another variable to specify its size. It even lets you do it with an uninitialised variable. It compiles OK when the array is one-dimensional, but when it's 2D or more, the compiler gets very confused.

    program_name='Ooops'

    define_variable

    integer d = 2
    integer b[d] (* Initialised variable used as size *)
    integer g
    integer h[g] (* Uninitialised variable used as size *)
    integer f[2][2] (* Good 2d array *)
    integer e[d][2] (* Bad 2d array *)
    integer c

    define_start

    c = b[1] (* OK *)
    c = b[3] (* Compiler error - out of bounds! *)
    c = h[1] (* OK *)
    c = h[2] (* Compiler error - out of bounds! *)
    c = f[1][1] (* OK *)
    c = e[1][1] (* Compiler error - dimension mismatch - *oops* *)

    It is obviously more appropriate to use a constant not a variable, so this is just a heads-up to help you spot your error if it happens to you!
  • Compiler misses wrong argument type

    The following code compiles without error despite the argument in the call to the function having the wrong type.

    PROGRAM_NAME='Oops'

    define_variable

    integer MyInteger

    define_function MyFunction(dev argDevice) {}

    define_start

    MyFunction(MyInteger)
  • Never delete the last button on a page

    If you create a new tpd3 file and delete the default Setup button, tpd3 crashes.

    If you add another button first then delete the Setup button, it's fine.
  • "Replace all" runs out of space

    If I select a chunk of repetitive text in the NS2 editor and "replace all" one word with a longer word, it runs out of space and fails to change the last couple of instances.

    eg trying replacing "a" with "bb" in a selection with just two lines

    a
    a

    The workaround is to select a couple of lines beyond what you want changing and check the result.
  • button_event[dTouchpanel,0] gets hold wrong

    The following code correctly reports the push and release but reports a hold with a button value of zero a couple of seconds later whether or not you hold the button down.

    If you replace the ",0" with any other meaningful code it works correctly.

    program_name = 'fred'

    define_device

    dTouchpanel = whatever

    define_event

    button_event[dTouchpanel,0]
    {
    push: send_string 0,"'push',itoa(button.input.channel)"
    release: send_string 0,"'release',itoa(button.input.channel)"
    hold[20]: send_string 0,"'hold',itoa(button.input.channel)"
    }
  • NS2 compiler can't parse include name immediately followed by brace

    if (whatever)
    {
    #include 'whatever.axi'} (* Fails - note no space *)

    if (whatever)
    {
    #include 'whatever.axi' } (* Compiles *)
  • NS2 Compiler reports error in "wrong place"

    Try to compile this and you get a syntax error at (B) instead of a "too many intialisers" error at (A) so it takes ages to work out what you did wrong! When (B) is absent, the error at (A) is notified.

    program_name='fred'

    define_variable

    integer x = {1,2} (* (A) *)
    integer y

    define_program

    y = x[1] (* (B) *)
  • switch/case inside a wait inside a function fails at runtime

    The following code causes a series of runtime errors. Calling the function from a wait does not appear to be relevant. Putting a switch/case inside a wait inside a function appears to be the key.

    program_name='Ooops'

    define_function a()
    {
    wait 1
    {
    switch (2)
    {
    case 3: {}
    }
    }
    }

    define_program

    wait 20 a()
  • sethollesetholle Posts: 66
    Known problems with structures and modules

    It seems to be that there is a problem with the debugger. I for instance can not watch the internal variables of a structure in debug. It does not show a value. Likewise with a module that you instance many times. There is no way to differentiate which is which so as to watch the variables inside a module. Is there a way around this? I have no problem watching regular variables in debugger.
  • All good points.

    Mark,

    You illustrate why learning to program NetLinx is so challenging. Have you sent your findings to AMX tech support?

    Most of your items are just 'the nature of the beast.'

    I have experienced all of what you have listed except for the modal page flip missing the release. Never tried it, but makes prefect sense. More a touch panel firmware issue than a NetLinx bug.

    Nice job.
  • All of these have been reported to AMX, some as long as three years ago.

    Update: I have now completed reviewing lots of my old bug reports and have found that quite a few have been corrected - so I haven't posted them here.
  • "Not defined" instead of "already defined"

    The following code prompts from the compiler the message "Symbol [Fred] not defined"
    instead of "Fred is already defined":

    program_name='Oops'

    define_function Fred()
    {}

    define_function Bert()
    {
    char Fred
    Fred = 2
    }
  • Possible to initialise a constant with a nonexistent identifier

    You can initialise a string with a nonexistent identifier as long as you wrap it in double-quotes.

    program_name='Oops'

    define_constant

    char a[] = "b" (* Compiles OK *)

    define_variable

    char c[] = "d" (* Symbol [D] not defined *)
  • Identical function names cause "major system error"

    If you define two functions with the same name, the compiler crashes with a meaningless error message "Major system error during code generation".

    Fortunately I'm not aware of any other circumstance which gives the same error, and the "Collapse All Fold Levels" button is great for finding the duplicate.

    I get this error quite often because I always make a new function by copying the header of an existing one and sometimes I forget to change the name to protect the innocent.
  • mpullinmpullin Posts: 949
    NS Studio closing unexpectedly

    I have NS Studio open and I'm using Device Notifications to track strings coming out of a virtual device. There is a certain action I can take on the TP for this virtual device that causes NS Studio to close right away. Obviously I'm not sure what the offending string is because NS closes too fast for me to see it.

    So here's what I did. In the String Data_Event for this device I inserted a SEND_STRING 0, "'trace:',DATA.TEXT" and instead of activating Device Notifications, I activated the Diagnostics. When I performed the action again, I saw a bunch of normal strings, and this:
    Line 7 :: SendString 0:0:0 too long 634 truncated to 274 - 10:23:46

    If Diagnostics can tell that it's about to print a string that's too big, why can't Device Notifications? The least NS could do is give me some intelligent error and crash, as opposed to just vanish without a trace. Also, I STILL can't see the string that's causing the problem.
  • DHawthorneDHawthorne Posts: 4,584
    mpullin wrote:
    I have NS Studio open and I'm using Device Notifications to track strings coming out of a virtual device. There is a certain action I can take on the TP for this virtual device that causes NS Studio to close right away. Obviously I'm not sure what the offending string is because NS closes too fast for me to see it.

    So here's what I did. In the String Data_Event for this device I inserted a SEND_STRING 0, "'trace:',DATA.TEXT" and instead of activating Device Notifications, I activated the Diagnostics. When I performed the action again, I saw a bunch of normal strings, and this:

    If Diagnostics can tell that it's about to print a string that's too big, why can't Device Notifications? The least NS could do is give me some intelligent error and crash, as opposed to just vanish without a trace. Also, I STILL can't see the string that's causing the problem.
    I think this is an issue with the volume of notifications. I have several perfectly working systems that if I turn all notifications on, I get that same "vanishing" crash. Studio and NetLinx Diagnostics have different thresholds that cause the crash, but both do it. You have to limit your notifications to just what you are watching - and if the device is extra chatty, you may be out of luck.
  • mpullinmpullin Posts: 949
    strings MIA
    DHawthorne wrote:
    You have to limit your notifications to just what you are watching - and if the device is extra chatty, you may be out of luck.

    I did this as a followup to my above 'bug complaint'. I listened only to strings from 33003:1:0. The result is depicted in this attachment:

    Anyone ever have this one before?
  • get_last fails inside a level_event

    The title says it. get_last returns bogus values when used inside a level_event. In other words:

    DEFINE_CONSTANT
    integer nAS16Levels[]=
    {
    4,
    5,
    8,
    9
    }

    DEFINE_EVENT
    LEVEL_EVENT[vdvAS16,nAS16Levels]
    {
    nLevelIndex = get_last(nAS16Levels)
    }

    This example if included in a program will compile and run... but nLevelIndex will not be accurately populated with the actual index of nAS16Levels that triggered the event. This has been a known bug for aeons... it was originally reported in cuneiform on a Babylonian clay tablet I think.
  • switch case inside wait
    The following code causes a series of runtime errors. Calling the function from a wait does not appear to be relevant. Putting a switch/case inside a wait inside a function appears to be the key.

    program_name='Ooops'

    define_function a()
    {
    wait 1
    {
    switch (2)
    {
    case 3: {}
    }
    }
    }

    define_program

    wait 20 a()


    Yes... the details are sketchy, but there is definitely a problem with using a switch case inside a wait, or possibly inside nested waits. select active works fine as a workaround.
  • The title says it. get_last returns bogus values when used inside a level_event.

    Yes, we all wish this would work.

    If you check the key word for Get_Last in NetLinx help, it indicates Get_Last is not supported in a Level_Event.
  • get_last
    B_Clements wrote:
    Yes, we all wish this would work.

    If you check the key word for Get_Last in NetLinx help, it indicates Get_Last is not supported in a Level_Event.

    Yes, as I said, this has been a known bug forever. But that does not mean everyone is necessarily aware of it. I did not know it was mentioned in the help file. However, my beef with that is that given how long this problem has existed and the apparent decision that it shall never be fixed... I think that the compiler should issue a warning when a programmer tries to do it. Otherwise it is syntactically correct and the program runs, making it difficult to troubleshoot when you actually encounter this problem first hand.
  • Get_Last is a Function!
    Yes, as I said, this has been a known bug forever. But that does not mean everyone is necessarily aware of it. I did not know it was mentioned in the help file. However, my beef with that is that given how long this problem has existed and the apparent decision that it shall never be fixed... I think that the compiler should issue a warning when a programmer tries to do it. Otherwise it is syntactically correct and the program runs, making it difficult to troubleshoot when you actually encounter this problem first hand.

    Jason, once you code NetLinx for as long as I have you get used to the inconsistencies. Having Get_Last work in a Level_Event is more of a feature request than a bug. If it was easy to fix, than it would have been long ago.

    I always recommend that you notify AMX tech support with your issues so they get officially documented. Many reports of the same issue usually generate a revision in a future release.
  • NS2 Enable UTF-8 format causes compiler failure

    In Netlinx Studio 2.5 (and earlier versions) if you switch on

    Settings / Preferences / Editor / Enable UTF-8 format to display Hebrew, Arabic, Cyrillic, and Han Characters

    and create any code file it won't compile but gives a series of three "unrecognised character" errors.

    This sounds wild but I've had it independently verified.

    If you need to use this feature, I think that the workaround is to create the file with this option switched off then switch it back on.
  • mpullinmpullin Posts: 949
    If you define two functions with the same name, the compiler crashes with a meaningless error message "Major system error during code generation".

    Fortunately I'm not aware of any other circumstance which gives the same error, and the "Collapse All Fold Levels" button is great for finding the duplicate.

    I have discovered that you will also get this error if you build a switch/case structure where the cases are strings and you use too many cases. I haven't determined what the limit is but it's somewhere between 10 and 20.
  • Major System Error - switch / case
    mpullin wrote:
    I have discovered that you will also get this error if you build a switch/case structure where the cases are strings and you use too many cases.

    This didn't sound quite right so I asked and mpullin kindly sent me his code and I hunted down that Major System Error (sounds like a character in a military comedy), and here it is.

    It's yet another variation of the "single character string" problem. What's odd is that I could have sworn this gave a runtime error not a compile time error; maybe NS2 has been improved:

    program_name='fred'

    define_variable

    char s[10]

    define_constant

    char s2[] = 'b'

    define_program

    switch(s)
    {
    //case 'a': (* Causes major system error *)
    //case s2: (* Causes major system error *)
    case 'cc': (* Has to be there *)
    {
    }
    }

    The compiler won't allow

    case "'a'":
    case "s2":

    and you can't use a variable as a case.

    So you just have to put the single character cases at the end of the list, or use something other than switch/case.
  • mpullinmpullin Posts: 949
    Apparently, it doesn't matter where the single characters are, they can't be in the same switch/case with multicharacter strings. This code produces the Major System Error:
    switch(CMD){
    		case 'PLAY':		PULSE[arr_COMCAST[ComcastX],1]
    		case 'STOP':		PULSE[arr_COMCAST[ComcastX],2]
    		case '<<':		PULSE[arr_COMCAST[ComcastX],4]
    		case '>>':		PULSE[arr_COMCAST[ComcastX],5]
    		case 'EXIT': 		PULSE[arr_COMCAST[ComcastX],8]
    		case 'CH+':		PULSE[arr_COMCAST[ComcastX],22]
    		case 'CH-':		PULSE[arr_COMCAST[ComcastX],23]
    		case 'PG+':		PULSE[arr_COMCAST[ComcastX],24]
    		case 'PG-':		PULSE[arr_COMCAST[ComcastX],25]
    		case 'A':		PULSE[arr_COMCAST[ComcastX],30]
    		case 'B':		PULSE[arr_COMCAST[ComcastX],31]
    		case 'C':		PULSE[arr_COMCAST[ComcastX],32]
    		case 'FAV':		PULSE[arr_COMCAST[ComcastX],35]
    		case 'LIVE':		PULSE[arr_COMCAST[ComcastX],39]
    		case 'LAST':		PULSE[arr_COMCAST[ComcastX],50]
    		case 'MENU':		PULSE[arr_COMCAST[ComcastX],54]
    		case 'INFO':		PULSE[arr_COMCAST[ComcastX],55]
    		case 'HELP':		PULSE[arr_COMCAST[ComcastX],56]
    		default:		PULSE[arr_COMCAST[ComcastX],(10+atoi("CMD"))]
    	    }
    
    But this is a-ok:
    switch("':',CMD"){
    		case ':PLAY':		PULSE[arr_COMCAST[ComcastX],1]
    		case ':STOP':		PULSE[arr_COMCAST[ComcastX],2]
    		case ':<<':		PULSE[arr_COMCAST[ComcastX],4]
    		case ':>>':		PULSE[arr_COMCAST[ComcastX],5]
    		case ':EXIT': 		PULSE[arr_COMCAST[ComcastX],8]
    		case ':CH+':		PULSE[arr_COMCAST[ComcastX],22]
    		case ':CH-':		PULSE[arr_COMCAST[ComcastX],23]
    		case ':PG+':		PULSE[arr_COMCAST[ComcastX],24]
    		case ':PG-':		PULSE[arr_COMCAST[ComcastX],25]
    		case ':A':		PULSE[arr_COMCAST[ComcastX],30]
    		case ':B':		PULSE[arr_COMCAST[ComcastX],31]
    		case ':C':		PULSE[arr_COMCAST[ComcastX],32]
    		case ':FAV':		PULSE[arr_COMCAST[ComcastX],35]
    		case ':LIVE':		PULSE[arr_COMCAST[ComcastX],39]
    		case ':LAST':		PULSE[arr_COMCAST[ComcastX],50]
    		case ':MENU':		PULSE[arr_COMCAST[ComcastX],54]
    		case ':INFO':		PULSE[arr_COMCAST[ComcastX],55]
    		case ':HELP':		PULSE[arr_COMCAST[ComcastX],56]
    		default:		PULSE[arr_COMCAST[ComcastX],(10+atoi("RIGHT_STRING(CMD,1)"))]
    	    }
    
    A useful tip/trick to get around this error, if you don't mind my saying so.
Sign In or Register to comment.