Which array triggered button? (How do you do your grids/matrixes?)
say you have a couple arrays of button numbers and you stack them on a button event, how can you figure out which array the button is in?
[code]
DEFINE_CONSTANT
btns1[] = [1,16,99]
btns2[] = [13,2,5]
BUTTON_EVENT[tp,btns1]
BUTTON_EVENT[tp,btns2]
{
PUSH:{
//was this btns1 or btns2?
}
}
[code]
if the buttons are in some kind of order, you can do math to figure it out, but is there any trick for GET_LAST or something like that?
This must come up all the time for grids of buttons, like a matrix switcher.
I did it with a bunch of math, but it was pain. At least now I have an include of a bunch of Grid functions.
I'm coming back to it a few months later, thinking there must be an easy way. But when I started, it turned out to be just as much work.
[code]
DEFINE_CONSTANT
btns1[] = [1,16,99]
btns2[] = [13,2,5]
BUTTON_EVENT[tp,btns1]
BUTTON_EVENT[tp,btns2]
{
PUSH:{
//was this btns1 or btns2?
}
}
[code]
if the buttons are in some kind of order, you can do math to figure it out, but is there any trick for GET_LAST or something like that?
This must come up all the time for grids of buttons, like a matrix switcher.
I did it with a bunch of math, but it was pain. At least now I have an include of a bunch of Grid functions.
I'm coming back to it a few months later, thinking there must be an easy way. But when I started, it turned out to be just as much work.
0
Comments
Here is one generic way to tell what row and column was pushed inside an array of grid buttons and it’s easily configurable.
DEFINE_DEVICE dvTp = 10001:1:0 DEFINE_CONSTANT INTEGER nGridButtons[] = { 11,12,13,14,15, // row 1 columns 1-5 21,22,23,24,25, // row 2 columns 1-5 31,32,33,34,35 // row 3 columns 1-5 } INTEGER nNumberOfRows = 3 INTEGER nNumberOfColumns = 5 DEFINE_EVENT BUTTON_EVENT[dvTP,nGridButtons] { PUSH: { INTEGER index INTEGER row INTEGER column index = GET_LAST(nGridButtons) row = index / nNumberOfColumns IF (index % nNumberOfColumns) {row++} IF (index % nNumberOfColumns = 0) {column = nNumberOfColumns} ELSE {column = (index % nNumberOfColumns)} SEND_STRING 0,"'BUTTON.INPUT.CHANNEL = ',ITOA(BUTTON.INPUT.CHANNEL)" SEND_STRING 0,"'Index = ',ITOA(index)" SEND_STRING 0,"'Row = ',ITOA(row)" SEND_STRING 0,"'Column = ',ITOA(column)" } }I’ve seen a better way of doing this calculation but I can’t remember where or how:
row = index / nNumberOfColumns IF (index % nNumberOfColumns) {row++}If anyone knows please post it.
BUTTON_EVENT[tp,0] { PUSH:{ SELECT { ACTIVE(get_last(btns1)): { // } ACTIVE(get_last(btns2)): { // } }I don't think that will work.
Took me way too long, but here are my functions with no IFs
DEFINE_FUNCTION INTEGER F_BTN_IS_IN_ROW(INTEGER _btn, INTEGER _numRows){ RETURN (_btn - 1) % (_numRows) + 1 } DEFINE_FUNCTION INTEGER F_BTN_IS_IN_COL(INTEGER _btn, INTEGER _numRows){ RETURN (_btn - 1 ) / (_numRows) + 1 }These are for the other way to align the grid (sometimes you aren't the one who numbers things):
{
1,4,7,
2,5,8,
3,6,9
}
If you are referring to the code I posted, it doesn't matter what the button numbers are. Button numbers themselves don't mean a thing in this case, they're just used as placeholders. It will work with whatever button numbers, whatever amount of rows, and whatever amount of columns. Aside from the constants, the code doesn't need to change.
I don't think those functions will work. Try pushing button 15 (button index 5) and it should be row 1 column 5. The functions above will return row 2 column 2.
Paul
Even trying it like this so that the arrays are built into the event table works in the same bizarre manner.
DEFINE_EVENT //BUTTON EVENT TP_ANI_ARRAY BUTTON_EVENT[vTest,nBtns1] BUTTON_EVENT[vTest,nBtns2] { PUSH: { SELECT { ACTIVE(get_last(nBtns1))://{1,16,99} { SEND_STRING 0,"'TEST btns1 BTN-[ ',itoa(get_last(nBtns1)),' ] :DEBUG<',itoa(__LINE__),'>'"; } ACTIVE(get_last(nBtns2))://{13,2,5}; { SEND_STRING 0,"'TEST btns2 BTN-[ ',itoa(get_last(nBtns2)),' ] :DEBUG<',itoa(__LINE__),'>'"; } ACTIVE(1): { SEND_STRING 0,"'TEST btns(1) BTN-[ ',itoa(BUTTON.INPUT.CHANNEL),' ] :DEBUG<',itoa(__LINE__),'>'"; } } } }INTEGER cSw_Btns[] = {11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, 44, 51, 52, 53, 54, 61, 62, 63, 64, 71, 72, 73, 74, 81, 82, 83, 84, 91, 92, 93, 94, 101, 102, 103, 104, 111, 112, 113, 114, 121, 122, 123, 124} BUTTON_EVENT [tpSwitch, cSw_Btns] { PUSH: { STACK_VAR INTEGER Input STACK_VAR INTEGER Output Input = Button.Input.Channel / 10 Output = Button.Input.Channel % 10 SEND_STRING dvSwitch, "ITOA(Input), '*', ITOA(Output), 'S'" } }This is not limited to numbers below 10, just change your divisor. It is much easier to understand in increments of 10 however. Does require consecutive button numbers, but that is no big deal IMO. Why write two button events and use a variable to store the value of the first one triggered when you can do it all in one event? On the other hand I don't really find occasion to use a grid of buttons very often.DEFINE_CONSTANT INTEGER OFFSET = 13 INTEGER NUM_ROWS = 10 INTEGER nGrid3[] = { 14,24,34,44,54,64,74,84,94,104,114,124 ,15,25,35,45,55,65,75,85,95,105,115,125 ,16,26,36,46,56,66,76,86,96,106,116,126 ,17,27,37,47,57,67,77,87,97,107,117,127 ,18,28,38,48,58,68,78,88,98,108,118,128 ,19,29,39,49,59,69,79,89,99,109,119,129 ,20,30,40,50,60,70,80,90,100,110,120,130 ,21,31,41,51,61,71,81,91,101,111,121,131 ,22,32,42,52,62,72,82,92,102,112,122,132 ,23,33,43,53,63,73,83,93,103,113,123,133 } DEFINE_EVENT BUTTON_EVENT[dv_TPs, nGrid3] { PUSH:{ LOCAL_VAR INTEGER chan LOCAL_VAR INTEGER ROW3 LOCAL_VAR INTEGER COLUMN3 //GL3 = GET_LAST(nGrid3) chan = BUTTON.INPUT.CHANNEL ROW3 = F_BTN_IS_IN_ROW(chan-offset, NUM_ROWS) COLUMN3 = F_BTN_IS_IN_COL(chan-offset, NUM_ROWS) SEND_STRING 0, "'BTN-', itoa(BUTTON.INPUT.CHANNEL), ' ROW-', ITOA(row3), ' COL-', ITOA(column3)" } }I'm going to write another set to work with GET_LAST...
PROGRAM_NAME='test' include'config' //include'incGrid' DEFINE_CONSTANT INTEGER OFFSET = 13 INTEGER NUM_ROWS = 10 INTEGER NUM_COLS = 12 INTEGER nGrid3[] = { 14,24,34,44,54,64,74,84,94,104,114,124 ,15,25,35,45,55,65,75,85,95,105,115,125 ,16,26,36,46,56,66,76,86,96,106,116,126 ,17,27,37,47,57,67,77,87,97,107,117,127 ,18,28,38,48,58,68,78,88,98,108,118,128 ,19,29,39,49,59,69,79,89,99,109,119,129 ,20,30,40,50,60,70,80,90,100,110,120,130 ,21,31,41,51,61,71,81,91,101,111,121,131 ,22,32,42,52,62,72,82,92,102,112,122,132 ,23,33,43,53,63,73,83,93,103,113,123,133 } DEFINE_FUNCTION INTEGER F_BTN_IS_IN_ROW(INTEGER _btn, INTEGER _numRows){ RETURN (_btn - 1) % (_numRows) + 1 } DEFINE_FUNCTION INTEGER F_BTN_IS_IN_COL(INTEGER _btn, INTEGER _numRows){ RETURN (_btn - 1 ) / (_numRows) + 1 } DEFINE_FUNCTION INTEGER F_IDX_IS_IN_ROW(INTEGER _btn, INTEGER _numCols){ RETURN (_btn - 1) / (_numCols) + 1 } DEFINE_FUNCTION INTEGER F_IDX_IS_IN_COL(INTEGER _btn, INTEGER _numCols){ RETURN (_btn - 1 ) % (_numCols) + 1 } DEFINE_EVENT BUTTON_EVENT[dv_TPs, nGrid3] { PUSH:{ LOCAL_VAR INTEGER chan LOCAL_VAR INTEGER ROW3 LOCAL_VAR INTEGER COL3 LOCAL_VAR INTEGER COLUMN3 LOCAL_VAR INTEGER GL3 GL3 = GET_LAST(nGrid3) chan = BUTTON.INPUT.CHANNEL ROW3 = F_BTN_IS_IN_ROW(chan-offset, NUM_ROWS) COLUMN3 = F_BTN_IS_IN_COL(chan-offset, NUM_ROWS) SEND_STRING 0, "'BTN-', itoa(BUTTON.INPUT.CHANNEL), ' ROW-', ITOA(row3), ' COL-', ITOA(column3)" ROW3 = F_IDX_IS_IN_ROW(GL3,NUM_COLS) COL3 = F_IDX_IS_IN_COL(GL3,NUM_COLS) SEND_STRING 0, "'BTN-', itoa(BUTTON.INPUT.CHANNEL), ' ROW-', ITOA(row3), ' COL-', ITOA(column3)" } }How did you work the feedback on this problem?
DEFINE CONSTANT INTEGER NumSwOuts = 4 DEFINE_VARIABLE VOLATILE INTEGER Sw_State[NumSwOuts] DEFINE_FUNCTION INTEGER FIND_Sw_Response(CHAR Buffer[], CHAR Response[]) { STACK_VAR LONG Len STACK_VAR LONG Count Len = LENGTH_ARRAY(Buffer) FOR (Count = 1; Count <= Len; Count++) { IF (Buffer[Count] == 'S' OR Buffer[Count] == 'X') { Response = LEFT_STRING(Buffer, Count) REMOVE_STRING(Buffer, Response, 1) RETURN TRUE } } RETURN FALSE } DEFINE_FUNCTION Switch_Feedback() { STACK_VAR INTEGER Len STACK_VAR INTEGER Count STACK_VAR INTEGER Input STACK_VAR INTEGER Output Len = MAX_LENGTH_ARRAY(cSw_Btns) FOR (Count = 1; Count <= Len; Count++) { Input = cSw_Btns[Count] / 10 Output = cSw_Btns[Count] % 10 [tpSwitch, cSw_Btns[Count]] = Sw_State[Output] == Input } } DEFINE_EVENT DATA_EVENT [dvSwitch] { ONLINE: { SEND_COMMAND dvSwitch, 'SET BAUD 9600,N,8,1 485 DISABLE' SEND_COMMAND dvSwitch, 'HSOFF' } STRING: { STACK_VAR CHAR Response[32] STACK_VAR INTEGER Output WHILE (FIND_Sw_Response(Sw_RxBuffer, Response)) { SELECT { ACTIVE (RIGHT_STRING(Response, 1) == 'S'): { Output = ATOI(REMOVE_STRING(Response, 'IN', 1)) IF (Output > 0 AND Output <= NumSwOuts) { Sw_State[Output] = ATOI(Response) } } } } } }nBtn1 = get_last (btns1);
nBtn2 = get_last (btns2);
if theres a match one var will be 0 and the other will hold the index value. Then if/else if
I stopped using the GET_LAST function a year or so ago, when I was getting inconsistent results from it with the code I was writing at that time. Of course I don't recall the exact issue I was a having, but I stopped trusting some innate Netlinx functions because they sometimes didn't work as expected, and became very frustrating to track down.
There was another one that was giving me fits but I can't remember it at the moment.
I suppose maybe the issues I encountered with those functions have since been resolved.
Given a consistent result, I agree your recommendation would be simpler.