Home AMX User Forum NetLinx Studio

turning on relays in startup code

I've got an NI-3100 that won't turn on a relay during startup code. If I put a command to start up the relay:

on[dvRelays,1]

...into the startup code stack, it does not turn the relay on and, in fact, won't execute any other statements after that statement. If I make this my last statment in the startup code stack, at least the rest of the initialization works OK, but it still won't execute the relay on command.

There's got to be a way to get a relay turned on at system startup, I just don't know the trick. Can someone point me in the right direction?

Thanks,

Comments

  • Why not do that in the online event?


    Data_Event[dvRELAYS]
    {
    ONLINE:
    {
    ON[dvRELAY,1]
    }
    }
  • As I understand it, you cannot count on the built-in devices in an NI-XX00 to be online at the time of startup code execution. Therefore it becomes necessary to utilize ONLINE events to get these things happen.
    DATA_EVENT[dvRelays]
    {
      ONLINE:
      { 
        ON[dvRelays,1]
      }
    }
    
    The same should be applied to setting up IR and 232 ports:
    DATA_EVENT[dvIR]
    { 
      ONLINE:
      { 
        SEND_COMMAND data.device,'SET MODE IR'  
        SEND_COMMAND data.device,'CARON'
      }
    }
    
  • Frankie wrote:
    Why not do that in the online event?

    Mostly because I'm fairly new to AMX programming, and I don't know any better. ;-)

    Thanks for the tip - I'll give it a whirl and confirm the fix to the forum.
  • DarksideDarkside Posts: 345
    You must use the online_event for this to work correctly!

    These devices are very likely NOT to be online at the time startup code runs and the command will be missed.

    You could try and create a wait to cover this 'device coming online' period....but this is basically exactly what the online_event is all about!

    :-)

    Using the online_event will ensure your command is issued only when the dev is online and not before.

    Very good practice to do it for all devices actually.
  • vincenvincen Posts: 526
    A good advice, when you write NetLinx program, remove completely the DEFINE_START section of your programs, it has no more reason to be there !! and it can be as you have discovered source of problems.

    If you need to configure a device at startup, you put it in a ONLINE event of the device.
    If you need to initialize a variable at startup, you put it in a ONLINE on master of system.

    My 2 cents tip of the day ;)

    Vinc
  • Populate tables in define_start
    vincen wrote:
    A good advice, when you write NetLinx program, remove completely the DEFINE_START section of your programs, it has no more reason to be there

    The point is good and well made but if you use table-driven logic you still need to populate the tables some time and define_start is the right place to call your Initialisation function.

    I guess I should explain table-driven coding; I find I use it more and more. My latest project has dozens of tables in the mainline describing the rooms, the devices, etc and typically one table in each device module - for the commands that drive the device.

    Use a table whenever you have repetitive information, and there tends to be a LOT of that in AV control systems code. For serial commands that might be the command string, the description of the command (for debugging purposes), the time to wait for the command to be executed, and the enumerated value of the state it will be in afterwards. Or whatever.

    The idea is that instead of writing lots of code to say what happens in each logical variation of whatever, you should create a table of information with flags saying what to do, and some code that consults the table instead of laboriously doing those things for each enumerated case.

    The key advantage is that the "doing what needs doing" code is written only once in one place (the code that interprets the table) and the "list of what needs doing" is listed in only one place (the code that populates the table.) It is particularly valuable when you suspect or expect that the rules might change later, or the code might be expected to drive more than one device, or the behaviour rules may be different in different rooms, or whatever.

    But to get to the point, the direct benefit is that code that looks like it works is much more likely to work in all cases than it would if the code laboriously spelled every case out one by one.

    What's a table? It's an array of structures. When you create a new table you need:

    define_constant

    <The enumerated instances in the array eg CommandPowerOn = 1, etc>
    <The constant that says how many commands you will have in the array>

    define_type

    <The struct that describes the commands>

    define_variable

    <The array of structs>

    define_function <The function to populate one command in the array>

    define_start

    <The function calls to populate the array>
  • DHawthorneDHawthorne Posts: 4,584
    vincen wrote:
    A good advice, when you write NetLinx program, remove completely the DEFINE_START section of your programs, it has no more reason to be there !! and it can be as you have discovered source of problems.

    If you need to configure a device at startup, you put it in a ONLINE event of the device.
    If you need to initialize a variable at startup, you put it in a ONLINE on master of system.

    My 2 cents tip of the day ;)

    Vinc?n

    No, you still need it for CREATE_BUFFER, and CREATE_LEVEL. I've also used it to populate data structures in modules (apply parameter data to an internal structure since you can't pass structures as a parameter). So it's not quite obsolete yet.
  • HedbergHedberg Posts: 671
    No, you still need it for CREATE_BUFFER, and CREATE_LEVEL. I've also used it to populate data structures in modules (apply parameter data to an internal structure since you can't pass structures as a parameter). So it's not quite obsolete yet.

    You don't need CREATE_BUFFER anymore though some say there is an efficiency advantage. Don't need CREATE_LEVEL either. I haven't used either in several years (except for the odd Axcent program). I find DEFINE_START useful on occasion, but not a lot. If it were no longer available, I'd get by.

    But, it's all a matter of preference, I'd say. If you try, you can probably find a way to do just about everything without resort to DEFINE_START, but there's surely nothing wrong with it if it's convenient and the pitfalls are kept in mind.
  • Joe HebertJoe Hebert Posts: 2,159
    Hedberg wrote:
    I find DEFINE_START useful on occasion, but not a lot. If it were no longer available, I'd get by.
    I was told that DEFINE_MODULEs need to be the last things in DEFINE_START. Did I hear wrong? Where else would you put them without DEFINE_START?
  • DHawthorneDHawthorne Posts: 4,584
    Joe Hebert wrote:
    I was told that DEFINE_MODULEs need to be the last things in DEFINE_START. Did I hear wrong? Where else would you put them without DEFINE_START?
    I'm pretty sure it doesn't matter where you put DEFINE_MODULE, as long as all their parameters are defined, and you were told that to insure any start up things were done before the modules loaded.
  • DHawthorneDHawthorne Posts: 4,584
    Hedberg wrote:
    You don't need CREATE_BUFFER anymore though some say there is an efficiency advantage. Don't need CREATE_LEVEL either. I haven't used either in several years (except for the odd Axcent program). I find DEFINE_START useful on occasion, but not a lot. If it were no longer available, I'd get by.

    But, it's all a matter of preference, I'd say. If you try, you can probably find a way to do just about everything without resort to DEFINE_START, but there's surely nothing wrong with it if it's convenient and the pitfalls are kept in mind.

    There is no other way to "read" the value of a level that is defined in a module (especially when you don't have the axs, but only a compiled tko) except for DEFINE_LEVEL. I admit, sometimesf it is just programming style, so I'm certainly not going to argue that there aren't other ways to do it. Just trying to say they do have their uses, and if you do use them that way, you have to put it in DEFINE_START.
  • Joe HebertJoe Hebert Posts: 2,159
    Hedberg wrote:
    You don't need CREATE_BUFFER anymore though some say there is an efficiency advantage.
    How do you get by without using CREATE_BUFFER when you need to buffer large amounts of data (anything larger than 16k)? The only place you can use CREATE_BUFFER is in DEFINE_START.
  • Joe Hebert wrote:
    How do you get by without using CREATE_BUFFER when you need to buffer large amounts of data (anything larger than 16k)? The only place you can use CREATE_BUFFER is in DEFINE_START.

    Is this the same as create_buffer in define start?

    Data_Event[RS_232]
    {
    String:
    {
    buffer="buffer,data.text"
    }

    }
  • mpullinmpullin Posts: 949
    Is this the same as create_buffer in define start?
    Yes, it is conceptually the same. If there are any performance differences I'm not aware of them, I hope someone else could answer that. Personally I always use CREATE_BUFFER in DEFINE_START section, create a function to parse the buffer, and call that function in DEFINE_PROGRAM.
  • Joe HebertJoe Hebert Posts: 2,159
    Is this the same as create_buffer in define start?
    Data_Event[RS_232]
    {
    String:
    {
    buffer="buffer,data.text"
    }

    }
    One would expect that to be the case but it?s not. We can?t concatenate anything over 15999 bytes, yet CREATE_BUFFER can. I don?t know why the limitation exists but here is code to prove it does:
    DEFINE_DEVICE
    dvTP		= 10001:1:0
    vdvBufferTest	= 33001:1:0
    
    DEFINE_VARIABLE
    CHAR cArray1[15000]
    CHAR cArray2[2000]
    CHAR cBuffer[65000]
    
    DEFINE_START
    SET_LENGTH_ARRAY(cArray1,15000)
    SET_LENGTH_ARRAY(cArray2,750)
    
    cBuffer = cArray1
    
    DEFINE_EVENT
    DATA_EVENT[vdvBufferTest] {
       STRING: {
          cBuffer = "cBuffer,DATA.TEXT"
          SEND_STRING 0, "'Length of cBuffer = ',ITOA(LENGTH_ARRAY(cBuffer))"
       }
    }
    
    BUTTON_EVENT[dvTP,1] {
       PUSH: {   
          SEND_STRING 0, 'Sending cArray2'
          SEND_STRING vdvBufferTest,cArray2
       }
    } 
    
    Here is the output when button 1 is pushed 3 times. It should grow by 750 bytes each time. Notice that the length never grows past 15999
    Line 1 :: Sending cArray2 - 12:37:40
    Line 2 :: Length of cBuffer = 15750 - 12:37:40
    Line 3 :: Sending cArray2 - 12:37:43
    Line 4 :: Length of cBuffer = 15999 - 12:37:43
    Line 5 :: Sending cArray2 - 12:37:44
    Line 6 :: Length of cBuffer = 15999 - 12:37:44

    So that being the case I believe you can?t do without CREATE_BUFFER and if we need CREATE_BUFFER then we can?t do without DEFINE_START since that?s the only place that CREATE_BUFFER can go. That?s my story and I?m sticking to it. :)
Sign In or Register to comment.