Learning how to do AMX modules
gravityhammer
Posts: 65
I'm new to AMX, but have been programming "the other guys" for 5 years. I have a job that is using a Biamp Nexia TC for audioconferencing. I need to learn how to make Netlinx modules, so since I programmed my own SIMPL+ Nexia conferencing module, I figured I would start here.
I an trying to use channels for input and feedback from the module, but I'm having trouble understanding how to send data like the current phone number back out of the module to the main. To add to my frustration, I've randomly downloaded some InConcert AMX modules to see what they did, only to inevitably discover that there isn't source code for the COMM portion. Have I just picked bad examples, or is this common for AMX-supplied modules?
I an trying to use channels for input and feedback from the module, but I'm having trouble understanding how to send data like the current phone number back out of the module to the main. To add to my frustration, I've randomly downloaded some InConcert AMX modules to see what they did, only to inevitably discover that there isn't source code for the COMM portion. Have I just picked bad examples, or is this common for AMX-supplied modules?
0
Comments
AMX Supplied comm modules will not include source. The UI modules included with most AMX modules are open source, but are really intended to be used as a reference guide for creating your own UI module that works with your project code. Not sure if you are permissions limited because of certification status, but you should search the forums and you will find several examples of open source modules that other posters have contributed to the community.
Good Luck!
Some ways of sending data back and forth is through SEND_STRING and SEND_COMMAND; when I write a module, I used SEND_COMMAND to the virtual for actually commands, such as getting the power status (SEND_COMMAND vdvDevice,'POWER?'), and then within the COMM module, I'd do a SEND_STRING to the virtual for feedback (SEND_STRING vdvDevice, 'POWER=1'). Of course, in the COMM, there is no STRING event for vdvDevice, and in the UI module there is no COMMAND event for the virtual device.
Of course, you could write a singular module where the UI and COMM is all in one file - easier, but a pain in my opinion and not the way of AMX standards. Also, you can use CHANNEL_EVENTs easily to do feedback and act upon things. Take this for example:
1. UI module asks COMM module what the power status is.
2. COMM module tells UI module what the power status is.
3. COMM module turns a channel on within the virtual device (i.e ON[vdvDevice,255])
4. UI module or main code has CHANNEL_EVENT[vdvDevice,255] and acts accordingly with it's ON or OFF sections.
Of course, this is just one way to skin the cat . . . as I'm sure you know from experience, there's many ways to do a single thing.
Hope this helps a little! Good luck!
Here are some other links that contain different official documents on module creation:
Module Example
How to write your own Netlinx Module
Adding functions to existing AMX modules using PASSTHRU
I plan on setting up the COMM module as a virtual device. In this module, how do I differentiate strings coming from the device versus strings coming from the UI module's "SEND_COMMAND"s?
EDIT: Or is it most preferable to include 2 virtual devices in the Comm module - one for the device interaction, and another for the UI interaction?
Here's a flow chart I just made real quick.
In my situation, I'm starting off with the dialer portion of the Nexia TC. Eventually, I'll add level and mute controls. Would it be best to have a Dialer UI and a separate Level UI that talk to the same Comm? If I do that, does the Master initiate multiple Comm instances, or is it smart enough to use only one instance of the Comm module?
I would have the dialer, level, whatever all in one module. The master sees however many modules you define - which should be one per real device. (Or, if you make it so - one per device set using arrays.) Unless you see an instance of only using the dialer, and no level control - you could have separate UI modules, but would not recommend it.
As you play with the AMX written modules you'll usually notice a 'Passthru' command. The Passthru command is written to let you send your own command to a module so it can be queued up and sent to the device. This is so that you don't throw commands at a device directly and risk sending data at the same time as the comm module and overflowing the device.
Welcome to the forums by the way!
I am working on my COMM module, which currently defines a virtual UI device and a regular device for the DSP. I'd like to direct multiple UI modules to this one device - for instance, I more than likely will have multiple fader channels to control, and I would like to (for simplicity sake) put each on it's own virtual device. This will require calling an individual instance of the UI module for each, correct? Or is it preferred to create an array of virtual devices, and call the UI module instance once for each type (i.e., one Dialer UI and one Fader UI)?
What are the advantages / disadvantages to using SEND_COMMAND between modules vs SEND_STRING?
If you look at modules written by AMX, you'll see that the COMM module has two parameters, the virtual and the real device; with the UI module you'll see multiple parameters, one of which is the same exact module defined in the COMM's parameters, and then sometimes an array of touch panels (or just one.) Think of the virtual that's defined in both as the interpreter as I'd said before - one guy handling all the information back and forth. Keep in mind UI modules are NOT required, they just make things a bit easier.
Review the flowchart a few posts up. You can write it however you want, but this is just a "standard" flow of modules. (Please someone chime in if I'm incorrect.)
In the comm/ui model use, with comms via a virtual device between modules, it really makes no difference. However, it allows for one to always be distinguished as a command to the device / comm module and the other to be the feedback from the device / comm module. You can do it separate but keep in mind that send_command or send_string will fire in BOTH modules - you can separate with send_command/string or do it by parsing, but the former is easier.
Sure. Would I'd like to do is have (obviously) only 1 module talking to my Biamp - the Comm module.
Different projects require different controls - and different quantities of those controls. On some, we may need to adjust 8 different level channels; on others, we may need to only do 1. The same goes for Dialers - we have up to 4 in a system, although we usually only have 1.
I would like to have a generic "level channel" control, and another generic "dialer" control. That way, I can have each level channel and each dialer on it's own virtual device, and reuse the same channels / levels across the virtual devices to control the Biamp (e.g., channel 1 may be vol up, and channel 2 vol down across all the virtual devices). I'm looking to have the Comm module look at *which* virtual device is sending the message in order to direct the Biamp to change the appropriate level channel.
Currently, the header of my Comm module looks like this:
and my Main program calls it with: where vdvDSPArray is defined prior:
The Fader module looks like: and is called with:
The good news is that it appears to work at first blush, with one fader. But this leads me to another question. You can include variables in module definitions, but how do you define that module in the main program? I have tried: and where iFader1Unit is a constant value of 1, but I get the following error when I compile: Is it possible to pass an integer in a module definition?
EDIT: OK - I feel a little dumb. Assigning iFader1Unit using: Under the variable definitions works fine.
I don't see a problem with what you're doing as far as having multiple virtuals, it should work. You just obviously need to write the code in the COMM module to decipher them, but that'll easily be done with a GET_LAST.
What does the index have to do with anything? You can use GET_LAST, or I wrote a function that checks a device against a dev array for a matching device to get the index. This way your array index doesn't have to match the port of the device you put in the array.
What do you mean by "call" as in "module I call it in?" What are you 'calling?'
I don't know your skills but I am guessing you fully understand events and the data_event handler, and this is where you are using the data.* struct?
Currently, I'm using the device port as the array index for two reasons: I do not plan to have multiple devices with the same port number talking to this module, and I would otherwise need a serial numbering system anyway - may as well use the port number.
By "call", I mean running the command. I "call" data.device.port in my data_event to determine (or to try to determine) the port of the device that sent the data.
How are you "calling" data.device.port? What "command?" I'm guessing you mean you are reading the value of it in a conditional or an assignment. Does your data event act on the entire array of vdevs? If you insist on using vdevs, try GET_LAST() or write an iterative match function to determine which device sent the data and see if that helps you.
COMM: 33333:1:0
fader 1: 33333:2:0
fader 2: 33333:3:0
fader 3: 33333:4:0
fader 4: 33333:5:0
What I can't seem to get configured is how to send the incoming value to the correct port only. For instance, if I get in the string: I want whichever level I'm using for my volume to go to 999 on fader 2 (vdv port 3) *only*. If I use this in my Comm module when my fader UI modules connect: iCurrentPortNum seems to always equal 1 or 2 - never any of the higher values.
That said, currently I have the port number passing as a parameter to the fader UI module.
I would like to keep each fader and each dialer on it's own vdv for scalability reasons. We have had large jobs with 4 dialers and 50+ faders, and it would be much more legible (IMO) to have each on it's own virtual device - for that matter, it would be difficult to fit all of the functionality on a single vdv.
I think you're going to gain a ton of knowledge by the time you're done with this project. Just to help out a bit with the terminology, What you described is actually only one virtual device (33333) with 5 ports (:1,:2,:3,:4,:5).
A virtual device only has 1 port by default, if you want it to use more you have to explicitly define that using the SET_VIRTUAL_PORT_COUNT command.
I think in this instance, instead of creating multiple ports for each fader within a device, you may want to consider using multiple "levels". That will cut down on your overhead a lot and I think it will accomplish the same goal.
--John
If I understand correctly, since you're re-using the same channels on a generic fader UI page to control different devices or faders, somewhere in there you're going to need to track the state of the touchpanel as to which device it's trying to control. In other words, if you're controlling fader 3 on device 1, you're going to need to select device 1 on the touchpanel, then fader 3, then use the controls vol up/vol down. If my assumptions are correct, then you can just use a multi-dimensional array or map to track the actual level or device you're trying to adjust. Are these assumptions correct or am I totally missing it?
--John
I get what you're saying about the multiple devices. I'll look at doing just the levels.
When I posted about using the channels, I'd planned on having the module handle the ramping functionality. Looks like it may be easier to let the touchpanel handle that, or am I thinking wrong here?
I'm changing my modules to only use different ports on a vdv (see - I'm learning ) if there are different instance or unit numbers on the different fader controls.
My biggest concern right now is how in the heck do I direct strings from my comm module back to the correct device for the proper UI module? I know that I will need at least two UI modules - one for faders and another for a dialer. If I try a [virtual device].number in my comm module, the value is 5. Where the heck would 5 come from? My device number is 33334!
When you have multiple modules interfacing with one other, how is the common module supposed to direct it's responses to the correct virtual device?
[virtual device].device.number
Things can be a little frustrating at first.
You know where the response came from right? You send it tot he correct module from where you got the response.