GET_LAST w/ virtual dev array
vining
Posts: 4,368
I just ran into a problem using GET_LAST w/ a virtual dev array. I assumed using GET_LAST would work to retrieve the index postion of the virual device initiating the online event or level event but it doesn't work as I expected. My virtuals all use the same dev.number and they vary by port only and from what I gather GET_LAST only checks the dev.number to return the array index not the entire DPS. Not a big problem since I just changed my get_last to var = data.device.port since they are in the same sequential order and numbers but I would have thought when using get_last on a dev array it would check the entire DPS not just the DEV.Number. I often like to keep like devices for module instances using the same dev number and just set_virtual_port_counts then rebuild. It just seemed easier but now I'm not so sure.
0
Comments
DEFINE_DEVICE //VIRTUAL KEYPADS. ONE FOR EACH ZONE (AP OUTPUT) IN SYSTEM. 16 ZONES / 16 VIRTUALS + A DUMMY OR BASE VIRTUAL FOR FILLERS #IF_NOT_DEFINED vMET_KPs //need 1 for each output zone vMETKP_Base = 33048:0:0 ; // based used to set virtual port count & act as a dummy in the array when real device doesn't exist vMETKP_1 = 33048:1:0 ; // zone 1 1 *)'Media Room', vMETKP_2 = 33048:2:0 ; // zone 2 2 *)'Family Room', vMETKP_3 = 33048:3:0 ; // zone 3 3 *)'1st FL GBed', vMETKP_4 = 33048:4:0 ; // zone 4 4 *)'Foyer', vMETKP_5 = 33048:5:0 ; // zone 5 5 *)'Dining Room', vMETKP_6 = 33048:6:0 ; // zone 6 6 *)'Patio (R)', vMETKP_7 = 33048:7:0 ; // zone 7 7 *)'Patio (L)', vMETKP_8 = 33048:8:0 ; // zone 8 8 *)'Master Bed', vMETKP_9 = 33048:9:0 ; // zone 9 9 *)'Master Bath', vMETKP_10 = 33048:10:0 ; // zone 10 10*)'MB Porch', vMETKP_11 = 33048:11:0 ; // zone 11 11*)'Purple Bed', vMETKP_12 = 33048:12:0 ; // zone 12 12*)'Tan Bed', vMETKP_13 = 33048:13:0 ; // zone 13 13*)'Hall Bath', vMETKP_14 = 33048:14:0 ; // zone 14 14*)'Blue Bed', vMETKP_15 = 33048:15:0 ; // zone 15 15*)'Guest''s Porch', vMETKP_16 = 33048:16:0 ; // zone 16 16*)'3rd Floor', #END_IF DEFINE_VARIABLE //DEV vMETKP_Arry[METKP_NUM_AP_ZONES] VOLATILE DEV vMETKP_Arry[METKP_NUM_AP_ZONES] = { vMETKP_1, // zone 1 1 *)'Media Room', vMETKP_2, // zone 2 2 *)'Family Room', vMETKP_3, // zone 3 3 *)'1st FL GBed', vMETKP_4, // zone 4 4 *)'Foyer', vMETKP_5, // zone 5 5 *)'Dining Room', vMETKP_6, // zone 6 6 *)'Patio (R)', vMETKP_7, // zone 7 7 *)'Patio (L)', vMETKP_8, // zone 8 8 *)'Master Bed', vMETKP_9, // zone 9 9 *)'Master Bath', vMETKP_10, // zone 10 10*)'MB Porch', vMETKP_11, // zone 11 11*)'Purple Bed', vMETKP_12, // zone 12 12*)'Tan Bed', vMETKP_13, // zone 13 13*)'Hall Bath', vMETKP_14, // zone 14 14*)'Blue Bed', vMETKP_15, // zone 15 15*)'Guest''s Porch', vMETKP_16 // zone 16 16*)'3rd Floor', } DEFINE_START //SET_VIRTUAL_LEVEL_COUNT(vMETKP_Base,METKP_NUM_AP_ZONES) ; SET_VIRTUAL_PORT_COUNT(vMETKP_Base,METKP_NUM_AP_ZONES) ; DEFINE_EVENT //DATA_EVENT[vMETKP_Arry] DATA_EVENT[vMETKP_Arry] { ONLINE: { STACK_VAR INTEGER vKP_Indx ; STACK_VAR INTEGER nDeviceID ; STACK_VAR INTEGER vKP_Indx_Port ; vKP_Indx = GET_LAST(vMETKP_Arry) ; vKP_Indx_Port = DATA.DEVICE.PORT ; fnMETKP_DeBug("'KP Online-1 vKP_Indx=',itoa(vKP_Indx),', DPS-Indx:',fnDEV_TO_STRING(vMETKP_Arry[vKP_Indx]),', DPS-Data.Device:',fnDEV_TO_STRING(DATA.DEVICE),' :DEBUG <',ITOA(__LINE__),'>'") ; fnMETKP_DeBug("'KP Online-2 vKP_Indx_Num=',itoa(vKP_Indx_Port),', DPS-Indx_Num-',fnDEV_TO_STRING(vMETKP_Arry[vKP_Indx_Port]),', DPS-Data.Device:',fnDEV_TO_STRING(DATA.DEVICE),' :DEBUG <',ITOA(__LINE__),'>'") ; if(dvMETKP_Arry[vKP_Indx] != vMETKP_Base) {//if the corresponding real device is a dummy don't set the virtuals levels, no need! SET_VIRTUAL_LEVEL_COUNT(vMETKP_Arry[vKP_Indx],METKP_NUM_FB_LVLs) ; } } }Diagnostics:
Also notice that GET_LAST starts at the end of the array while looking for a match not the beginning. Since GET_LAST apparently only cares about dev.number of the DPS it see index postion 16 as the match every time. So if you're going to use virtuals like this don't use nVirtual_Indx= GET_LAST(vVirtual_Arry) ; use nVirtual_Indx= DATA.DEVICE.PORT instead.
Paul.
Well someone at AMX must have thought it was a useful idea/method and that's why they gave us the SET_VRTUAL_PORT_COUNT command to allow us to do this. Changing the dev.number or dev.port gives each virtual a different D:P:S. The olny downside I see isn't really to do with changing ports instead of numbers but that GET_LAST on dev arrays doesn't actually compare all the devs paremeters. It only compares dev.numbers and not the complete D:P:S.
What if you have devs on different masters with the same D:P: and different system numbers and you build an array of these devs on the different masters GET_LAST won't work on them either. I think using GET_LAST on dev arrays the function should check the entire D:P:S not just the first parameter of the 3.
If GET_LAST worked properly then using this method makes following code a bit easier IMHO. If you working on code and you know the dev.number and want to look at the virtual for say KP 16 then that's the port, easy to follow, not 33026 (starting number) + 16 = ??.
I didn't say it shouldn't be allowed. Obviously there are times when you absolutely need the capability of having a virtual device with multiple ports. But it sounds like what you are doing is using the port number to differentiate between virtual devices rather than the device number, and now finding the unintended consequences of that. If they are different devices then they should have different device numbers. If its the same device with multiple ports then that is how is should be coded. Again, I see no advantage in doing this. If there is one, let us know.
I wouldn't do that. Different devices get different device numbers unless you like opening Pandora's box just to see what's inside. Its these types of programming errors that can cause very difficult, hard to trace bugs and I am just not that masochistic.
Seems like a strained example. When using get_last I don't care about anything but an index. As long as the correct index comes back then I am happy. I generally don't do arithmetic on virtual device numbers ever. The way I address my virtuals is at the very end of programming before installation I highlight the whole column and hit Alt+M. The numbers are more or less arbitrary and IMHO adding significance to arbitrariness is asking for trouble. It sounds like you might be one of those programmers that thinks its clever to use the channel number of a button to recall a TV station with the excuse that you can tell the station just by looking at the channel number. Down this road lies madness.
Paul.
As the appointed goodwill ambassador of GET_LAST(), I feel the need to defend her honor.
GET_LAST() with an array of virtual devices even with the same device number and different ports works fine for me. DUET modules use this method all the time.
You didn’t post any code that we could actually compile and test but I think the problem is most likely in your code someplace and not GET_LAST().
Here is the code that I tested against:
DEFINE_DEVICE vdvPort1 = 33001:1:0 vdvPort2 = 33001:2:0 vdvPort3 = 33001:3:0 vdvPort4 = 33001:4:0 vdvPort5 = 33001:5:0 vdvPort6 = 33001:6:0 vdvPort7 = 33001:7:0 vdvPort8 = 33001:8:0 vdvPort9 = 33001:9:0 vdvPort10 = 33001:10:0 vdvPort11 = 33001:11:0 vdvPort12 = 33001:12:0 vdvPort13 = 33001:13:0 vdvPort14 = 33001:14:0 vdvPort15 = 33001:15:0 vdvPort16 = 33001:16:0 DEFINE_VARIABLE VOLATILE DEV vdvArray[] = { vdvPort1, vdvPort2, vdvPort3, vdvPort4, vdvPort5, vdvPort6, vdvPort7, vdvPort8, vdvPort9, vdvPort10, vdvPort11, vdvPort12, vdvPort13, vdvPort14, vdvPort15, vdvPort16 } DEFINE_START SET_VIRTUAL_PORT_COUNT(vdvPort1,16) ; DEFINE_EVENT DATA_EVENT[vdvArray] { ONLINE: { SEND_STRING 0, "'Index=',ITOA(GET_LAST(vdvArray)),': Port=',ITOA(DATA.DEVICE.PORT)" } }And here are the results which are exactly as I would expect them to be. A virtual device comes online and then a debug statement using GET_LAST() is printed correctly and then the next device comes online and a debug statement and so on. If you swap vdvPort1 and vdvPort16 in the vdvArray then you’ll see that index 16 port 1 comes online first and then 2-15 and the last device to come online is index 1 port 16. Everything seems to report as expected.
If you look at the first three lines of your output the 2 debug messages look correct after port 1 comes online. But then the rest of the 16 ports come online before we see any more of your debug messages. There is something fishy going on like maybe a wait or something someplace after the first device comes online? It’s hard to tell since you’re not showing us enough of the picture.
If you run the code I posted are your results different than mine?
Here's the entire .axi. I have to run out now and play so I'll look through my code and see if maybe I duplicated a virtual and then test your code if I find nothing.
There was one or two times that I thought the code (GET_LAST) worked properly and my fears subsided, then I ran this last test which obviously didn't work. I'd love nothing more than to have GET_LAST work on the entire D:P:S but even if I duplicated the virtual or had a wait somewhere how can you explain the results of side by side comparison. It obviously isn't working in this example and I can think of anything that could cause this in code.
PROGRAM_NAME='VAV_MET_KPs' (***********************************************************) (* FILE CREATED ON: 09/09/2007 AT: 09:26:51 *) (***********************************************************) (* FILE_LAST_MODIFIED_ON: 07/30/2008 AT: 09:52:07 *) (***********************************************************) DEFINE_DEVICE //METREAU KEYPADS. ONE FOR EACH PHYSICAL KEYPAD #DEFINE METKP_AXI #IF_NOT_DEFINED MET_KPs //MET-6Ns USE 2 DEVICE IDs dvMETKP_1 = 162:1:0 ; //master bath dvMETKP_2 = 164:1:0 ; //master porch door dvMETKP_3 = 166:1:0 ; //purple bed dvMETKP_4 = 168:1:0 ; //blue bed room dvMETKP_5 = 170:1:0 ; //blue bed porch dvMETKP_6 = 172:1:0 ; //2nd fl hall bath dvMETKP_7 = 174:1:0 ; //pasqaule's room dvMETKP_8 = 176:1:0 ; // dvMETKP_9 = 178:1:0 ; // dvMETKP_10 = 180:1:0 ; // dvMETKP_11 = 182:1:0 ; //................... #END_IF DEFINE_DEVICE //VIRTUAL KEYPADS. ONE FOR EACH ZONE (AP OUTPUT) IN SYSTEM. 16 ZONES / 16 VIRTUALS + A DUMMY OR BASE VIRTUAL FOR FILLERS #IF_NOT_DEFINED vMET_KPs //need 1 for each output zone vMETKP_Base = 33048:0:0 ; // based used to set virtual port count & act as a dummy in the array when real device doesn't exist vMETKP_1 = 33048:1:0 ; // zone 1 1 *)'Media Room', vMETKP_2 = 33048:2:0 ; // zone 2 2 *)'Family Room', vMETKP_3 = 33048:3:0 ; // zone 3 3 *)'1st FL GBed', vMETKP_4 = 33048:4:0 ; // zone 4 4 *)'Foyer', vMETKP_5 = 33048:5:0 ; // zone 5 5 *)'Dining Room', vMETKP_6 = 33048:6:0 ; // zone 6 6 *)'Patio (R)', vMETKP_7 = 33048:7:0 ; // zone 7 7 *)'Patio (L)', vMETKP_8 = 33048:8:0 ; // zone 8 8 *)'Master Bed', vMETKP_9 = 33048:9:0 ; // zone 9 9 *)'Master Bath', vMETKP_10 = 33048:10:0 ; // zone 10 10*)'MB Porch', vMETKP_11 = 33048:11:0 ; // zone 11 11*)'Purple Bed', vMETKP_12 = 33048:12:0 ; // zone 12 12*)'Tan Bed', vMETKP_13 = 33048:13:0 ; // zone 13 13*)'Hall Bath', vMETKP_14 = 33048:14:0 ; // zone 14 14*)'Blue Bed', vMETKP_15 = 33048:15:0 ; // zone 15 15*)'Guest''s Porch', vMETKP_16 = 33048:16:0 ; // zone 16 16*)'3rd Floor', #END_IF DEFINE_CONSTANT //NUMBER KPs & AP ZONES METKP_NUM_KPs = 11 ; METKP_NUM_AP_ZONES = 16 ; DEFINE_CONSTANT //BUTTON POINTERS METKP_BTN_1 = 1 ; METKP_BTN_2 = 2 ; METKP_BTN_3 = 3 ; METKP_BTN_4 = 4 ; METKP_BTN_5 = 5 ; METKP_BTN_6 = 6 ; METKP_BTN_7 = 7 ; METKP_BTN_8 = 8 ; METKP_BTN_9 = 9 ; METKP_BTN_10 = 10 ; METKP_BTN_11 = 11 ; METKP_BTN_12 = 12 ; METKP_BTN_13 = 13 ; METKP_BTN_14 = 14 ; METKP_BTN_UP = 7 ; METKP_BTN_DN = 8 ; METKP_BTN_LEFT = 9 ; METKP_BTN_RIGHT = 10 ; METKP_BTN_CENTER = 11 ; METKP_BTN_ROTATE_R = 12 ; METKP_BTN_ROTATE_L = 13 ; DEFINE_CONSTANT //AP KP BUTTON POINTERS //KEYPADS KP_AP_POWER_BTN = 1 ; KP_AP_VOLDN_BTN = 2 ; KP_AP_VOLUP_BTN = 3 ; KP_AP_VMUTE_BTN = 4 ; KP_AP_SRC_BCK_BTN = 5 ; KP_AP_SRC_FWD_BTN = 6 ; KP_AP_SPARE_BTN_7 = 7 ; KP_AP_SPARE_BTN_8 = 8 ; KP_AP_SPARE_BTN_9 = 9 ; KP_AP_MUTE_ALL = 10 ; KP_AP_BTN_1 = 11 ; KP_AP_BTN_2 = 12 ; KP_AP_BTN_3 = 13 ; KP_AP_BTN_4 = 14 ; KP_AP_BTN_5 = 15 ; KP_AP_BTN_6 = 16 ; KP_AP_BTN_7 = 17 ; KP_AP_BTN_8 = 18 ; KP_AP_BTN_9 = 19 ; KP_AP_BTN_10 = 20 ; KP_AP_BTN_SRC_1 = 21 ; KP_AP_BTN_SRC_2 = 22 ; KP_AP_BTN_SRC_3 = 23 ; KP_AP_BTN_SRC_4 = 24 ; KP_AP_BTN_SRC_5 = 25 ; KP_AP_BTN_SRC_6 = 26 ; KP_AP_BTN_SRC_7 = 27 ; KP_AP_BTN_SRC_8 = 28 ; KP_AP_BTN_SRC_9 = 29 ; KP_AP_BTN_SRC_10 = 30 ; KP_AP_BTN_SRC_11 = 31 ; KP_AP_BTN_SRC_12 = 32 ; KP_AP_BTN_SRC_13 = 33 ; KP_AP_BTN_SRC_14 = 34 ; KP_AP_BTN_SRC_15 = 35 ; KP_AP_BTN_SRC_16 = 36 ; KP_AP_BTN_SRC_17 = 37 ; KP_AP_BTN_SRC_18 = 38 ; DEFINE_CONSTANT //LEVEL POINTER METKP_NUM_FB_LVLs = 14 ; //from keypad via dvMETKP_Arry to this file METKP_LVL_DISPLY = 1 ;//KP device level window for volume level display METKP_LVL_WHEEL = 2 ;//KP volume level from wheel to this file for coversion and sending to module. //from module via vMETKP_Arry to this file METKP_LVL_FBVOL = 1 ;//used to send volume FB from module to this file for FB METKP_LVL_FBMUT = 2 ;//used to send mute FB from module to this file for FB METKP_LVL_FBSRC = 3 ;//used to send source FB from module to this file for FB //from this file to vMETKP_Arry METKP_LVL_TX_VOL = 8 ;//used to send volume level from keypad wheel to the module to set the AP volume DEFINE_TYPE //_sMETKPs STRUCTURE _sMETKPs { INTEGER nVol ; INTEGER nMute ; INTEGER nSrc ; } DEFINE_VARIABLE //_sMETKPs sMETKPs[METKP_NUM_AP_ZONES] PERSISTENT _sMETKPs sMETKPs[METKP_NUM_AP_ZONES] ; DEFINE_VARIABLE //INTEGER nDeBug_KPs INTEGER nMETKP_OK_LVL VOLATILE INTEGER nMETKP_DeBug = 1 ; #WARN 'nDeBug_KPs set to 1' VOLATILE INTEGER nMETKP_OK_LVL = 0 ; DEFINE_VARIABLE //INTEGER nMETKP_TypeArry[METKP_NUM_KPs] //no type then offline, type = online VOLATILE INTEGER nMETKP_TypeArry[METKP_NUM_AP_ZONES] ; DEFINE_VARIABLE //DEV dvMETKP_Arry[METKP_NUM_AP_ZONES] VOLATILE DEV dvMETKP_Arry[METKP_NUM_AP_ZONES] = //ADD DUMMIES AND PUT REAL KPS IN ORDER OF ZONES //no KP in zone, then put in the dummy (base virtual) { //notice the real device order. They match zones not DPS order vMETKP_Base, // zone 1 1 *)'Media Room', vMETKP_Base, // zone 2 2 *)'Family Room', vMETKP_Base, // zone 3 3 *)'1st FL GBed', vMETKP_Base, // zone 4 4 *)'Foyer', vMETKP_Base, // zone 5 5 *)'Dining Room', vMETKP_Base, // zone 6 6 *)'Patio (R)', vMETKP_Base, // zone 7 7 *)'Patio (L)', vMETKP_Base, // zone 8 8 *)'Master Bed', dvMETKP_1, // zone 9 9 *)'Master Bath', dvMETKP_2, // zone 10 10*)'MB Porch', dvMETKP_3, // zone 11 11*)'Purple Bed', dvMETKP_7, // zone 12 12*)'Tan Bed', dvMETKP_6, // zone 13 13*)'Hall Bath', dvMETKP_4, // zone 14 14*)'Blue Bed', dvMETKP_5, // zone 15 15*)'Guest''s Porch', vMETKP_Base // zone 16 16*)'3rd Floor', } DEFINE_VARIABLE //DEV vMETKP_Arry[METKP_NUM_AP_ZONES] VOLATILE DEV vMETKP_Arry[METKP_NUM_AP_ZONES] = { vMETKP_1, // zone 1 1 *)'Media Room', vMETKP_2, // zone 2 2 *)'Family Room', vMETKP_3, // zone 3 3 *)'1st FL GBed', vMETKP_4, // zone 4 4 *)'Foyer', vMETKP_5, // zone 5 5 *)'Dining Room', vMETKP_6, // zone 6 6 *)'Patio (R)', vMETKP_7, // zone 7 7 *)'Patio (L)', vMETKP_8, // zone 8 8 *)'Master Bed', vMETKP_9, // zone 9 9 *)'Master Bath', vMETKP_10, // zone 10 10*)'MB Porch', vMETKP_11, // zone 11 11*)'Purple Bed', vMETKP_12, // zone 12 12*)'Tan Bed', vMETKP_13, // zone 13 13*)'Hall Bath', vMETKP_14, // zone 14 14*)'Blue Bed', vMETKP_15, // zone 15 15*)'Guest''s Porch', vMETKP_16 // zone 16 16*)'3rd Floor', } DEFINE_VARIABLE //INTEGER nMETKP_APBtnArry[] VOLATILE INTEGER nMETKP_APBtnArry[] = //these can't change unless the module is changed! { 1, // Power Zone On/Off 2, // Mute 3, // Direct Input Select 10*)'XM Radio', 4, // Direct Input Select 9 *)'AM/FM 2', 5, // Source BACK 6, // Source FWD 7, // 8, // 9, // 10, // 11, // 12, // Vol Up 13, // Vol Dwn 14 // } // only 14 button on metreau keypads // 15, // // 16, // // 17, // // 18, // // 19, // //MUTE ALL // 20, // // 21, // Direct Input Select 1_*)'Off', // 22, // Direct Input Select 2 )' Vortex 1', // 23, // Direct Input Select 3 *)'Vortex 2', // 24, // Direct Input Select 4 *)'Bar CD', // 25, // Direct Input Select 5 *)'Media DVD/CD // 26, // Direct Input Select 6 *)'MBed DVD/CD' // 27, // Direct Input Select 7 *)'Bar iPod', // 28, // Direct Input Select 8 *)'AM/FM 1', , // 29, // Direct Input Select 9 *)'AM/FM 2', // 30, // Direct Input Select 10*)'XM Radio', // 31, // Direct Input Select 11*)'Cable Music' // 32, // Direct Input Select 12*)'Sound B', // 33, // Direct Input Select 13// // 34, // Direct Input Select 14// // 35, // Direct Input Select 15// // 36, // Direct Input Select 16// // 37, // Direct Input Select 17// // 38 // Direct Input Select 18// // } DEFINE_FUNCTION fnMETKP_DeBug(CHAR iStr[]) { if(nMETKP_DeBug) { SEND_STRING 0,"'MET_KPs.axi DEBUG: ',iStr" ; } RETURN ; } DEFINE_FUNCTION fnMETKP_DoFB(INTEGER iKP_Zone,INTEGER iLVL_Chnl,INTEGER iLVL_Value) { SWITCH(iLVL_Chnl) { CASE METKP_LVL_FBVOL: { sMETKPs[iKP_Zone].nVol = iLVL_Value ; if(!nMETKP_OK_LVL) { if(sMETKPs[iKP_Zone].nSrc > 1) { SEND_LEVEL dvMETKP_Arry[iKP_Zone],METKP_LVL_DISPLY,TYPE_CAST(iLVL_Value * 2.55) ; } else { SEND_LEVEL dvMETKP_Arry[iKP_Zone],METKP_LVL_DISPLY,0 ; } } } CASE METKP_LVL_FBMUT: { sMETKPs[iKP_Zone].nMute = iLVL_Value ; [dvMETKP_Arry[iKP_Zone],METKP_LVL_FBVOL ] = sMETKPs[iKP_Zone].nMute ; [dvMETKP_Arry[iKP_Zone],1] = (sMETKPs[iKP_Zone].nSrc > 1) ; } CASE METKP_LVL_FBSRC: { sMETKPs[iKP_Zone].nSrc = iLVL_Value ; [dvMETKP_Arry[iKP_Zone],1] = (sMETKPs[iKP_Zone].nSrc > 1) ; [dvMETKP_Arry[iKP_Zone],3] = (sMETKPs[iKP_Zone].nSrc == 10) ; [dvMETKP_Arry[iKP_Zone],4] = (sMETKPs[iKP_Zone].nSrc == 11) ; } } RETURN ; } DEFINE_FUNCTION fnMETKP_UpdateKP(INTEGER iKP_Indx) { STACK_VAR INTEGER n ; //STACK_VAR INTEGER i ; STACK_VAR INTEGER nKPCount ; STACK_VAR INTEGER nLoopStart ; if(iKP_Indx) { nKPCount = iKP_Indx ; nLoopStart = iKP_Indx ; } else { nKPCount = METKP_NUM_AP_ZONES ; nLoopStart = 1 ; } for(n = nLoopStart ; n <= nKPCount ; n++) { if(dvMETKP_Arry[n] != vMETKP_Base) { fnMETKP_DoFB(n,METKP_LVL_FBVOL,sMETKPs[n].nVol) ; fnMETKP_DoFB(n,METKP_LVL_FBMUT,sMETKPs[n].nMute) ; fnMETKP_DoFB(n,METKP_LVL_FBSRC,sMETKPs[n].nSrc) ; //for(i = 1 ; i <= METKP_NUM_FB_LVLs ; i++) // { // //fnMETKP_DoFB(INTEGER iKP_Zone,INTEGER iLVL_Chnl,INTEGER iLVL_Value) // } } } } DEFINE_START //SET_VIRTUAL_LEVEL_COUNT(vMETKP_Base,METKP_NUM_AP_ZONES) ; SET_VIRTUAL_PORT_COUNT(vMETKP_Base,METKP_NUM_AP_ZONES) ; DEFINE_EVENT //DATA_EVENT[vMETKP_Arry] DATA_EVENT[vMETKP_Arry] { ONLINE: { STACK_VAR INTEGER nVirtKP_Indx ; nVirtKP_Indx = DATA.DEVICE.PORT ; fnMETKP_DeBug("'KP Online- Indx=',itoa(nVirtKP_Indx),', DPS-:',fnDEV_TO_STRING(vMETKP_Arry[nVirtKP_Indx]),' :DEBUG <',ITOA(__LINE__),'>'") ; if(dvMETKP_Arry[nVirtKP_Indx] != vMETKP_Base) {//if the corresponding real device is a dummy don't set the virtuals levels, no need! SET_VIRTUAL_LEVEL_COUNT(vMETKP_Arry[nVirtKP_Indx],METKP_NUM_FB_LVLs) ; } } } DEFINE_EVENT //DATA_EVENT[dvMETKP_Arry] DATA_EVENT[dvMETKP_Arry] { ONLINE: { STACK_VAR INTEGER nKP_Indx ; STACK_VAR INTEGER nDeviceID ; nKP_Indx = GET_LAST(dvMETKP_Arry) ; if(dvMETKP_Arry[nKP_Indx] != vMETKP_Base) {//if the corresponding real device is a dummy don't set the virtuals levels, no need! nMETKP_TypeArry[nKP_Indx] = (DEVICE_ID(dvMETKP_Arry[nKP_Indx]) - 168) ; //Set Brightness level for all LEDs (pushbuttons and levels indicator bar), for both On and Off states. SEND_COMMAND dvMETKP_Arry[nKP_Indx],'@BRT-24,0' ;//@BRT-<on brightness (0-32)>,<off brightness (0-32)> //Set Brightness level for Navigation Wheel LED, for both On and Off states. SEND_COMMAND dvMETKP_Arry[nKP_Indx],'@WBRT-30,0' ;//‘@WBRT-<on brightness (0-32)>,<off brightness (0-32)>’ SEND_COMMAND dvMETKP_Arry[nKP_Indx],'BMODE-0' ; (* Sets the bargraph mode: Syntax: 'BMODE-<bargraph mode 0-9>' Sets the specified bargraph to operate in one of the following modes: 0 = (default) normal bar mode 1 = normal dot mode (only one peak LED on at a time) 2 = special bar mode (a level of 1-32 still has first LED on) 3 = special dot mode (a level of 1-32 still has first LED on) 4 = inverse normal bar mode 5 = inverse normal dot mode 6 = inverse special bar mode 7 = inverse special dot mode 8 = individual element, discrete mode 9 = inverse individual element, discrete mode Example: SEND_COMMAND keypad,'BMODE-0' Sets the bargraph mode to default mode. *) fnMETKP_UpdateKP(nKP_Indx) ; } } OFFLINE: { STACK_VAR INTEGER nKP_Indx ; nKP_Indx = GET_LAST(dvMETKP_Arry) ; nMETKP_TypeArry[nKP_Indx] = 0 ; } } DEFINE_EVENT //BUTTON_EVENT [dvMETKP_Arry,nMETKP_APBtnArry] BUTTON_EVENT [dvMETKP_Arry,nMETKP_APBtnArry] { PUSH : { STACK_VAR INTEGER nBtn ; STACK_VAR INTEGER nKP_Indx ; nBtn = GET_LAST(nMETKP_APBtnArry) ; nKP_Indx = GET_LAST(dvMETKP_Arry) ; SWITCH(nMETKP_TypeArry[nKP_Indx]) { CASE METKP_TYPE_MET6N://BUTTONS 1-13 { fnMETKP_DeBug("'KP MET6N Zone-',itoa(nKP_Indx),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Indx]),', PUSHED_CHNL-',itoa(nBtn),' :DEBUG <',ITOA(__LINE__),'>'") ; if(sMETKPs[nKP_Indx].nSrc > 1 || nBtn == METKP_BTN_1) //already on or the power btn { SELECT /// CHANGE ANY BUTTONS YOU MUST ALSO CHANGE THE RELEASE !!!!!! { ACTIVE(nBtn == METKP_BTN_1): { DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_POWER_BTN,DO_PUSH_TIMED_5S_MAX) ; } ACTIVE(nBtn == METKP_BTN_2): { DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_VMUTE_BTN,DO_PUSH_TIMED_5S_MAX) ; } ACTIVE(nBtn == METKP_BTN_3): { DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_BTN_SRC_10 ,DO_PUSH_TIMED_5S_MAX) ; } ACTIVE(nBtn == METKP_BTN_4): { DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_BTN_SRC_11 ,DO_PUSH_TIMED_5S_MAX) ; } ACTIVE(nBtn == METKP_BTN_5): { TO[dvMETKP_Arry[nKP_Indx],nBtn] ; DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_SRC_BCK_BTN ,DO_PUSH_TIMED_5S_MAX) ; } ACTIVE(nBtn == METKP_BTN_6): { TO[dvMETKP_Arry[nKP_Indx],nBtn] ; DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_SRC_FWD_BTN,DO_PUSH_TIMED_5S_MAX) ; } ACTIVE(nBtn == METKP_BTN_7): {DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_VOLUP_BTN,DO_PUSH_TIMED_5S_MAX) ;} //METKP_BTN_UP ACTIVE(nBtn == METKP_BTN_8): {DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_VOLDN_BTN,DO_PUSH_TIMED_5S_MAX) ;} //METKP_BTN_DN ACTIVE(nBtn == METKP_BTN_9): {DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_VOLDN_BTN,DO_PUSH_TIMED_5S_MAX) ;} //METKP_BTN_LEFT ACTIVE(nBtn == METKP_BTN_10):{DO_PUSH_TIMED(vMETKP_Arry[nKP_Indx],KP_AP_VOLUP_BTN,DO_PUSH_TIMED_5S_MAX) ;} //METKP_BTN_RIGHT ACTIVE(nBtn == METKP_BTN_11):{} //METKP_BTN_CENTER ACTIVE(nBtn == METKP_BTN_12 || nBtn == METKP_BTN_13)://METKP_BTN_ROTATE_R //METKP_BTN_ROTATE_L { nMETKP_OK_LVL = 1 ; } ACTIVE(1)://Do Nothing, impossible to occur! { fnMETKP_DeBug("'PUSHED_CHNL-',itoa(nBtn ),', NON SUPPORTED CHANNEL, HOW? :DEBUG <',ITOA(__LINE__),'>'") ; } } } } CASE METKP_TYPE_MET7://BUTTONS 1-8 { fnMETKP_DeBug("'KP MET7 Zone-',itoa(nKP_Indx),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Indx]),', PUSHED_CHNL-',itoa(nBtn),' :DEBUG <',ITOA(__LINE__),'>'") ; SELECT { ACTIVE(nBtn == METKP_BTN_1):{} ACTIVE(nBtn == METKP_BTN_2):{} ACTIVE(nBtn == METKP_BTN_3):{} ACTIVE(nBtn == METKP_BTN_4):{} ACTIVE(nBtn == METKP_BTN_5):{} ACTIVE(nBtn == METKP_BTN_6):{} ACTIVE(nBtn == METKP_BTN_7):{} ACTIVE(nBtn == METKP_BTN_8):{} ACTIVE(1)://Do Nothing, impossible to occur! { fnMETKP_DeBug("'PUSHED_CHNL-',itoa(nBtn ),', NON SUPPORTED CHANNEL, HOW? :DEBUG <',ITOA(__LINE__),'>'") ; } } } CASE METKP_TYPE_MET13://BUTTONS 1-14 { fnMETKP_DeBug("'KP MET13 Zone-',itoa(nKP_Indx),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Indx]),', PUSHED_CHNL-',itoa(nBtn),' :DEBUG <',ITOA(__LINE__),'>'") ; SELECT { ACTIVE(nBtn == METKP_BTN_1):{} ACTIVE(nBtn == METKP_BTN_2):{} ACTIVE(nBtn == METKP_BTN_3):{} ACTIVE(nBtn == METKP_BTN_4):{} ACTIVE(nBtn == METKP_BTN_5):{} ACTIVE(nBtn == METKP_BTN_6):{} ACTIVE(nBtn == METKP_BTN_7):{} ACTIVE(nBtn == METKP_BTN_8):{} ACTIVE(nBtn == METKP_BTN_9):{} ACTIVE(nBtn == METKP_BTN_10):{} ACTIVE(nBtn == METKP_BTN_11):{} ACTIVE(nBtn == METKP_BTN_12):{} ACTIVE(nBtn == METKP_BTN_13):{} ACTIVE(nBtn == METKP_BTN_14):{} ACTIVE(1)://Do Nothing, impossible to occur! { fnMETKP_DeBug("'PUSHED_CHNL-',itoa(nBtn ),', NON SUPPORTED CHANNEL, HOW? :DEBUG <',ITOA(__LINE__),'>'") ; } } } DEFAULT: { fnMETKP_DeBug("'KP Err! No KP Type! Zone-',itoa(nKP_Indx),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Indx]),', PUSHED_CHNL-',itoa(nBtn),' :DEBUG <',ITOA(__LINE__),'>'") ; } } } RELEASE: { STACK_VAR INTEGER nBtn ; STACK_VAR INTEGER nKP_Indx ; nBtn = GET_LAST(nMETKP_APBtnArry) ; nKP_Indx = GET_LAST(dvMETKP_Arry) ; SWITCH(nMETKP_TypeArry[nKP_Indx]) { CASE METKP_TYPE_MET6N://BUTTONS 1-13 { fnMETKP_DeBug("'KP MET6N Zone-',itoa(nKP_Indx),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Indx]),', RELEASED_CHNL-',itoa(nBtn),' :DEBUG <',ITOA(__LINE__),'>'") ; SELECT { ACTIVE(nBtn == METKP_BTN_1): { DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_POWER_BTN) ; } ACTIVE(nBtn == METKP_BTN_2): { DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_VMUTE_BTN) ; } ACTIVE(nBtn == METKP_BTN_3): { DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_BTN_SRC_10) ; } ACTIVE(nBtn == METKP_BTN_4): { DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_BTN_SRC_11) ; } ACTIVE(nBtn == METKP_BTN_5): { DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_SRC_BCK_BTN) ; } ACTIVE(nBtn == METKP_BTN_6): { DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_SRC_FWD_BTN) ; } ACTIVE(nBtn == METKP_BTN_7): {DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_VOLUP_BTN) ;} //METKP_BTN_UP ACTIVE(nBtn == METKP_BTN_8): {DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_VOLDN_BTN) ;} //METKP_BTN_DN ACTIVE(nBtn == METKP_BTN_9): {DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_VOLDN_BTN) ;} //METKP_BTN_LEFT ACTIVE(nBtn == METKP_BTN_10):{DO_RELEASE(vMETKP_Arry[nKP_Indx],KP_AP_VOLUP_BTN) ;} //METKP_BTN_RIGHT ACTIVE(nBtn == METKP_BTN_11):{} //METKP_BTN_CENTER ACTIVE(nBtn == METKP_BTN_12 || nBtn == METKP_BTN_13): //METKP_BTN_ROTATE_R //METKP_BTN_ROTATE_L { nMETKP_OK_LVL = 0 ; } ACTIVE(1)://Do Nothing, impossible to occur! { fnMETKP_DeBug("'PUSHED_CHNL-',itoa(nBtn ),', NON SUPPORTED CHANNEL, HOW? :DEBUG <',ITOA(__LINE__),'>'") ; } } } CASE METKP_TYPE_MET7://BUTTONS 1-8 { fnMETKP_DeBug("'KP MET7 Zone-',itoa(nKP_Indx),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Indx]),', RELEASED_CHNL-',itoa(nBtn),' :DEBUG <',ITOA(__LINE__),'>'") ; SELECT { ACTIVE(nBtn == METKP_BTN_1):{} ACTIVE(nBtn == METKP_BTN_2):{} ACTIVE(nBtn == METKP_BTN_3):{} ACTIVE(nBtn == METKP_BTN_4):{} ACTIVE(nBtn == METKP_BTN_5):{} ACTIVE(nBtn == METKP_BTN_6):{} ACTIVE(nBtn == METKP_BTN_7):{} ACTIVE(nBtn == METKP_BTN_8):{} ACTIVE(1)://Do Nothing, impossible to occur! { fnMETKP_DeBug("'RELEASE_CHNL-',itoa(nBtn ),', NON SUPPORTED CHANNEL, HOW? :DEBUG <',ITOA(__LINE__),'>'") ; } } } CASE METKP_TYPE_MET13://BUTTON 1-14 { fnMETKP_DeBug("'KP MET13 Zone-',itoa(nKP_Indx),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Indx]),', RELEASED_CHNL-',itoa(nBtn),' :DEBUG <',ITOA(__LINE__),'>'") ; SELECT { ACTIVE(nBtn == METKP_BTN_1):{} ACTIVE(nBtn == METKP_BTN_2):{} ACTIVE(nBtn == METKP_BTN_3):{} ACTIVE(nBtn == METKP_BTN_4):{} ACTIVE(nBtn == METKP_BTN_5):{} ACTIVE(nBtn == METKP_BTN_6):{} ACTIVE(nBtn == METKP_BTN_7):{} ACTIVE(nBtn == METKP_BTN_8):{} ACTIVE(nBtn == METKP_BTN_9):{} ACTIVE(nBtn == METKP_BTN_10):{} ACTIVE(nBtn == METKP_BTN_11):{} ACTIVE(nBtn == METKP_BTN_12):{} ACTIVE(nBtn == METKP_BTN_13):{} ACTIVE(nBtn == METKP_BTN_14):{} ACTIVE(1)://Do Nothing, impossible to occur! { fnMETKP_DeBug("'RELEASE_CHNL-',itoa(nBtn ),', NON SUPPORTED CHANNEL, HOW? :DEBUG <',ITOA(__LINE__),'>'") ; } } } DEFAULT: { fnMETKP_DeBug("'KP Err! No KP Type! Zone-',itoa(nKP_Indx),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Indx]),', RELEASED_CHNL-',itoa(nBtn),' :DEBUG <',ITOA(__LINE__),'>'") ; } } } } DEFINE_EVENT //LEVEL_EVENT LEVEL_EVENT [vMETKP_Arry,0] LEVEL_EVENT [dvMETKP_Arry,METKP_LVL_WHEEL]//= 2 { STACK_VAR INTEGER nKP_Zone ; LOCAL_VAR INTEGER nKP_LevelWheel ; nKP_LevelWheel = LEVEL.VALUE ; if(nMETKP_OK_LVL) { nKP_Zone = GET_LAST(dvMETKP_Arry) ; fnMETKP_DeBug("'KP Zone-',itoa(nKP_Zone),', DPS-',fnDEV_TO_STRING(dvMETKP_Arry[nKP_Zone]),', RX LVL CHNL-',itoa(LEVEL.INPUT.LEVEL),', VALUE-',itoa(LEVEL.VALUE),':DEBUG <',ITOA(__LINE__),'>'") ; SEND_LEVEL dvMETKP_Arry[nKP_Zone],METKP_LVL_DISPLY,LEVEL.VALUE ; SEND_LEVEL vMETKP_Arry[nKP_Zone],METKP_LVL_TX_VOL,TYPE_CAST(LEVEL.VALUE / 2.55) ;//convert to base 100 } else { fnMETKP_DeBug("'KP Zone-',itoa(nKP_Zone),', RX LVL ERR! nMETKP_OK_LVL = 0, CHNL-',itoa(LEVEL.INPUT.LEVEL),', VALUE-',itoa(LEVEL.VALUE),':DEBUG <',ITOA(__LINE__),'>'") ; } } DEFINE_EVENT //LEVEL_EVENT [vMETKP_Arry,1,2,3 LEVEL_EVENT [vMETKP_Arry,METKP_LVL_FBVOL]//= 1 ; LEVEL_EVENT [vMETKP_Arry,METKP_LVL_FBMUT]//= 2 ; LEVEL_EVENT [vMETKP_Arry,METKP_LVL_FBSRC]//= 3 ; { STACK_VAR INTEGER nKP_Zone ; nKP_Zone = LEVEL.SOURCEDEV.PORT ; fnMETKP_DeBug("'KP-',itoa(nKP_Zone),', DPS-',fnDEV_TO_STRING(vMETKP_Arry[nKP_Zone]),', RX LVL CHNL-',itoa(LEVEL.INPUT.LEVEL),', VALUE-',itoa(LEVEL.VALUE),':DEBUG <',ITOA(__LINE__),'>'") ; fnMETKP_DoFB(nKP_Zone,LEVEL.INPUT.LEVEL,LEVEL.VALUE) ; } DEFINE_PROGRAM //EMPTY (*(VAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAV)*) (*( THE END )*) (*(VAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAV)*)a-riot42 wrote: I wasn't reffering to doing math on a virtual in code but rather in my head when doing diagnotics and setting up notification options. I know if I want to watch zone 16's virtual and can just type that in with out thinking too hard otherwise I don't care what numbers they are.
My other thought is that something else happening during the initialization sequences is goofing up the online events; overrunning a buffer or stalling the message queue.
I think I know why the there's a delay for port's higher than 1 coming online. The online event doesn't trigger until you call set_virtual_port_count(), so those devices don't come online until define_start runs.
I used to use multiple ports on virtual devices, but I ran into some weird issues with certain AMX modules, including one that refused to function at all on anything other than port 1. I haven't tried it in a few years, though I'm tempted to do so again since all of the few AMX-sourced modules I use at this point are Duet based, and I don't recall having any problems with any of my own modules. It'd make things a bit neater.
When you get down to it, virtually everything you aren't controlling over IP is a device with multiple ports. It's either a NI series controller of some kind or a netlinx control card of some kind, or a touchpanel of some kind. The distinction you're drawing here is artificial.
I don't follow. A controller device has a device ID of 5001 and you access the different ports using the D:P:S nomenclature but since its the same device the device number doesn't change. If you open the online tree you will see each virtual device has a different device number, not the same device number with a different port. I don't think the distinction between a device, port and system is artificial at least not in my experience. A dev is a structure with these three fields I believe, and using them for purposes other than what they were designed could lead to a lot of hair pulling. Netlinx gives you enough rope to hang yourself, but that doesn't mean you should.
Paul
If you number your keypad virtuals at say 33101 through 33116 then doesn't that accomplishe the same thing without having to contort the DPS paradigm?
Paul
Anyway back to the issue. I went through my code and didn't see any duplicated virtuals and then loaded the newest NI3100 firimware. I was running v3.50.430 and now I'm running v3.50.439. Of course now I can't reproduce the error but I don't think it was fixed by the firmware change. I think it's just a flaky issue.
I was thinking that it could be caused by my base DPS used in the SET_VIRT_PORT_COUNT since that was 33048:0:0. I was thinking maybe the "0" for the port might screw up the function. Of course here I think the function would only care about the dev.number but who knows. I wanted to use this as my dummy DPS which is why I set the port to zero but I now set it to 1 and created a legitimate dummy outside the DPS range of the used keypads. Still changing it back and forth from 0 to 1 I still couldn't replicate the error. I do feel that using a DPS with a legitimate port number is probably better and it's also what Joe used. Otherwise the both code blocks are pretty much the same and his worked while mine didn't. Maybe his gremlins were sleeping while mine were up and active. Now today they're back to sleep.
rfletcher wrote: That's what I was thinking too and probably the case.
I'm sorry, reading that again I don't think I did a good job of explaining what I meant clearly. Let me try again.
If I understood you correctly, you are saying here that you should not use multiple ports on a virtual device unless the device you are controlling has multiple ports. However, at the base level nearly every non-virtual device we can control has multiple ports, be it an NI controller, a control card, the master and it's IP ports, or a touch panel, or some other native netlinx device. It's only when you abstract out a layer and ignore the serial port (or whatever interface you're using) itself that it appears you have devices with only a single port.
So either multiple ports on a virtual device should never be used to control anything, or it's ok to use multiple ports on a virtual device to control anything, but saying that multiple virtual ports should only be used with devices that have multiple ports doesn't seem to make any sense to me, as there are (almost) no non-virtual devices that have only a single port.
Hopefully that makes a bit more sense...
Duet modules use different ports for outputs on a single switch for instance but they still use the same device number for the same device. In Duet if you had two switchers and wanted to do what Vining is doing it would look like this:
get_last will work with any device array, it just returns the index of the device that last triggered the event. That's why I don't think the issue has anything to do with get_last and may be one of those hard to trace bugs that only crop up in certain circumstances caused by doing unorthodox programming. Like you mention get_last has no issues differentiating between devices with different port numbers but same device number so obviously get_last isn't the problem here.
Paul
Guy goes to a doctor and say, "it hurts when I move my arm like this." Doctor responds, "then don't move your arm like that." I thought that joke was funny when I was about five, these days I find it about as funny as a rubber crutch.
Granted it may be considered unorthodox by a real programmer and when I find one I'll ask him or her what they think but for now I'd just like to know why something that by the books should work, doesn't. It may be very well be a bug and maybe I can't do this the way I want and that's ok. It very well may be my code and that's fine too. But for now there's an issue and it would be nice to know why and just because it's not something you do doesn't make it wrong or unorthodox it's just not something you do and the rest of this imaginary issue you have with it is just in your head and that's ok too.