EricInCanada Posted January 9, 2022 Share Posted January 9, 2022 (edited) I'm hoping to ask for your help optimizing a project before I embark on creating a big mess of nested If statements. I am building a physical control interface for the Artemis SBS Bridge Simulator, using an Arduino Mega. When a button is pushed on the control panel the Arduino sends a command over serial to the PC where an AutoIT scrip is waiting to execute the corresponding keystroke or mouse movement. I have this working in a basic hard-coded way (using this very helpful forum post from 2018), but I'd now like to build a GUI to make the tool usable without editing code. The user will select from a dropdown which function will run when the button attached a specific pin is pressed. See very basic screenshot attached, but imagine this going on for a large number of buttons. The challenge is that there are 54 pins on the Arduino Mega, and probably about 60 game actions each one could do. So doing this just with a bunch of nested IF statements will bloat the code and make it very difficult to maintain. If I add a new function, I'll have to add it as an list item to 54 different GUI controls, and then update 54 "If" statements to make sure that function could be assigned to any pin. If $NewMsg = "Pin1" then If GUICtrlRead($Pin1) = "Warp1" then Warp1() If GUICtrlRead($Pin1) = "Warp2" then Warp2() If GUICtrlRead($Pin1) = "Warp3" then Warp3() If GUICtrlRead($Pin1) = "Warp4" then Warp4() If GUICtrlRead($Pin1) = "FullStop" then FullStop() ;and so on EndIf If $NewMsg = "Pin2" then If GUICtrlRead($Pin2) = "Warp1" then Warp1() If GUICtrlRead($Pin2) = "Warp2" then Warp2() If GUICtrlRead($Pin2) = "Warp3" then Warp3() If GUICtrlRead($Pin2) = "Warp4" then Warp4() If GUICtrlRead($Pin2) = "FullStop" then FullStop() ;and so on EndIf There has to be a better way! Ideally I would: When loading the GUI, step through each dropdown control and add the same "List" items to all of them. When a new string is received over serial, find the dropdown with Name matching that string, and run the function with name matching the current selection in that dropdown Save the user's dropdown selections (in an .ini file, XML or similar?) and load them next time. I don't know how to achieve this in AutoIT. Are there control arrays, or other tricks in AutoIT to make this code cleaner? I appreciate any help to suggest a more elegant method to handle this, or any reading I should do in the AutoIT docs to think about this differently. Edited January 12, 2022 by EricInCanada Removed lock Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted January 9, 2022 Moderators Share Posted January 9, 2022 Welcome to the AutoIt forum. Unfortunately you appear to have missed the Forum rules on your way in. Please read them now - particularly the bit about not discussing game automation - and then you will understand why you will get no help and this thread will now be locked. See you soon with a legitimate question I hope. The Moderation team Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted January 11, 2022 Moderators Share Posted January 11, 2022 EricInCanada, After due consideration, sparked by a polite and explanative PM from the OP (take note others!), I have decided that this thread deals essentially with Arduino-AutoIt interfaces and does not specifically automate the game in any way. So I have reopened it. M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
Nine Posted January 11, 2022 Share Posted January 11, 2022 (edited) How about using Call(GUICtrlRead($PinX)) If you have multiple $Pin buttons, make it in an array like in this thread. Edited January 11, 2022 by Nine “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
BigDaddyO Posted January 11, 2022 Share Posted January 11, 2022 (edited) Here is the simplest way I can think of. Though, I know there is also a way to create dropdowns within a listview which would let you see everything easier but that would involve some forum searching. expandcollapse popupOpt("GUIOnEventMode", 1) ;Use Event mode to call functions directly #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <GuiComboBox.au3> Global $sPins, $sFunctions $iTotalPins = IniRead(@ScriptDir & "\Config.ini", "Global", "TotalPins", 0) For $i = 1 to $iTotalPins $sPins &= "|" & $i Next $aFunctions = IniReadSection(@ScriptDir & "\Config.ini", "Functions") For $i = 1 to UBound($aFunctions) - 1 $sFunctions &= "|" & $aFunctions[$i][1] Next $hGUI = GUICreate("Pinout Control", 300, 100) GUISetOnEvent($GUI_EVENT_CLOSE, "_ExitApp") GUICtrlCreateLabel("Pin#", 10, 13, 60, 17, $SS_CENTER) $hCmboPIN = GUICtrlCreateCombo("", 10, 30, 60, 20) GUICtrlSetOnEvent(-1, "_PinSelect") GUICtrlSetData($hCmboPIN, $sPins) GUICtrlCreateLabel("Function", 100, 13, 140, 17, $SS_CENTER) $hCmboFUNC = GUICtrlCreateCombo("", 100, 30, 140, 20) GUICtrlSetOnEvent(-1, "_FunctionSelect") GUICtrlSetData($hCmboFUNC, $sFunctions) GUICtrlCreateButton("Listen", 10, 70, 100, 20) GUICtrlSetOnEvent(-1, "_Listen") GUISetState(@SW_SHOW, $hGUI) While 1 sleep(100) WEnd Func _Listen() $aUserFunctions = IniReadSection(@ScriptDir & "\Config.ini", "User Config") Local $NewMsg While 1 ;$NewMsg = Get Pin somehow?? For $i = 1 to UBound($aUserFunctions) - 1 If $NewMsg = "Pin" & $aUserFunctions[$i][0] Then Call($aUserFunctions[$i][1]) Sleep(10) Next WEnd EndFunc Func _PinSelect() _GUICtrlComboBox_SetEditText($hCmboFUNC, IniRead(@ScriptDir & "\Config.ini", "User Config", GUICtrlRead($hCmboPIN), "Unassigned")) EndFunc Func _FunctionSelect() IniWrite(@ScriptDir & "\Config.ini", "User Config", GUICtrlRead($hCmboPIN), GUICtrlRead($hCmboFUNC)) EndFunc Func _ExitApp() Exit EndFunc ini file format "Config.ini" [Global] TotalPins=54 [Functions] 0=Unassigned 1=Warp1 2=Warp2 3=Full Stop [User Config] 1=Warp1 2=Warp2 3=Unassigned 4=Unassigned 5=Full Stop 10=Warp1 Edited January 11, 2022 by BigDaddyO added listen but don't know how the $NewMsg is populated Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted January 11, 2022 Moderators Share Posted January 11, 2022 Hi, 4 minutes ago, BigDaddyO said: a way to create dropdowns within a listview You might be thinking of my GUIListViewEx UDF - the link is in my sig. M23 Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind Open spoiler to see my UDFs: Spoiler ArrayMultiColSort ---- Sort arrays on multiple columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
EricInCanada Posted January 12, 2022 Author Share Posted January 12, 2022 This is excellent, thank you. The Call function is exactly what I needed, because it allows me to call a function with a name that won't be known until runtime. That was a big "Aha!" moment, so I'm making progress now. What I've done is build a big array of Combo boxes, where the array index matches the pin number. Every box is populated with the same list of functions: For $index = 2 to 25 $LabelD[$index] = GUICtrlCreateLabel("D" & $index, 8, ($index*20)-7, 24, 12) $ControlDefault = IniRead(@ScriptDir & "\Settings.ini", "General", "PinDPress" & $index, "Not Assigned") $PinDPress[$index] = GUICtrlCreateCombo($ControlDefault, 32, ($index*20)-15, 112, 25, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL)) GUICtrlSetData(-1, $ListOfButtonFunctions) Next Once I've parsed the pin number out of the serial message, I can grab the contents of the corresponding Combo box, and then call the matching function: If StringLeft($NewMsg, 5) = "PinDP" Then $PinNumber = Int(StringMid($NewMsg,6)) Call(GUICtrlRead($PinDPress[$PinNumber])) EndIf EndIf I've also got the INI working based on BigDaddyO's post above (thank you!) and the thing is pretty much functional now. I realize GUI event mode might have made this a little more elegant, I'll keep this in mind in the future. Link to comment Share on other sites More sharing options...
EricInCanada Posted January 12, 2022 Author Share Posted January 12, 2022 Main thing I'll be dealing with now is smoothing out the Serial coms. Buttons and switches are no problem, they involve so little data. But a potentiometer has to spam the serial buffer with a lot of packets while it's moving. This should be fine because the buffer on both sides is easily large enough to handle it, and even a 9600 baud connection is pretty quick. But in practice so far it's dodgy: commands are missed and the software state ends up out of sync from the physical control interface. Link to comment Share on other sites More sharing options...
EricInCanada Posted January 12, 2022 Author Share Posted January 12, 2022 Update on the serial issue. Two fixes combined worked to avoid the lag problem: Manually sent a Carriage Return character ("\r") in every message, which prevents the buffer from filling with two or more packets not separated by a delimitator of any kind. Discovered that "Mouse Down" followed by "Mouse Up" executes faster that a "Click", which makes a difference when moving a control across the screen with many clicks in succession. Maybe add Sleep(1) just for good measure. Realized that there's no point having the Arduino send instructions faster than the refresh rate of the monitor I'm using, so in the arduino code I added "Current Milis" count check to only send a new instruction for the control if 33ms has passed since the last time it send one. This means that for a rapid movement of the potentiometer from off to full, it is sending perhaps only a dozen packets, rather than all 1024 in the 10-bit resolution read. if(A0active == true) { NewA0 = (FloatA0*analogRead(A0)) + ((1-FloatA0)*NewA0); NewA0 = NewA0; unsigned long currentMillis = millis(); if(NewA0 != OldA0 && currentMillis - previousMillis >= 33) { Serial.print("PinA00" + String(NewA0) + "\r"); previousMillis = currentMillis; OldA0 = NewA0; } Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now