I want to make a program in autoit with a GUI - 2 buttons: the first button must refresh a web page (Ex: Google page) every 3 seconds, the second button must stop the refresh and do some operations on the web page. I'm ok with the first button, but I cannot exit from the loop with the second button and execute the operation I want. Can someone help me? Thanks a lot! This is the code:
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
$Form1 = GUICreate("Example", 190, 133, 192, 124)
GUISetBkColor(0xFFFF00)
$Button1 = GUICtrlCreateButton("UPDATE", 3, 31 ,179, 37, 0)
$Button2 = GUICtrlCreateButton("EXECUTE", 3, 80 ,179, 37, 0)
GUICtrlSetColor(-1, 0x0000FF)
GUICtrlSetBkColor(-1, 0x00FF00)
GUICtrlSetCursor (-1, 0)
GUICtrlSetColor(-1, 0x000000)
GUISetState(#SW_SHOW)
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $button1
HotKeySet("{x}", "_Exit") ; Sets a shortcut to kill the script quickly. ESC
Opt("WinTitleMatchMode", 3) ; This is to tell the script to only refresh the EXACT window, incase there are similar windows. Such as: Window 1, Window 2.
While 1 ; This begins a While LOOP
Sleep(3000) ; Tell the script to pause for 3 seconds
$title = WinGetTitle("Google - Mozilla Firefox", "") ; Grabs the exactly title and saves it to a variable to do an If statement against.
If WinExists($title) Then ; Check to see if the desired window is running.
WinActivate($title) ; If it is running, first activate the window.
WinWaitActive($title) ; This tells the script to not send the refresh key (F5) until the window has appeared.
Send("{F5}") ; This sends the F5 key to refresh the window.
Else ; This is an else statement to tell the script to do a different operation if the window is not running.
Sleep(10) ; Just a filler item to wait until the desired window is running.
EndIf ; End the If statement to continue the script.
WEnd ; Close the While LOOP
Func _Exit() ; This is the function that is linked to the kill switch, ESC. It tells the script to perform the following actions.
ExitLoop ; Block pressing "x"
EndFunc ; Close the function up.
Case $button2
ExitLoop ; stop the loop and make operations below
Send("{TAB}")
Send("^v")
EndSwitch
WEnd
Something like this?
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
Global $Go2 = True
$Form1 = GUICreate("Example", 190, 133, 192, 124)
GUISetBkColor(0xFFFF00)
$Button1 = GUICtrlCreateButton("UPDATE", 3, 31, 179, 37, 0)
$Button2 = GUICtrlCreateButton("EXECUTE", 3, 80, 179, 37, 0)
GUICtrlSetColor(-1, 0x0000FF)
GUICtrlSetBkColor(-1, 0x00FF00)
GUICtrlSetCursor(-1, 0)
GUICtrlSetColor(-1, 0x000000)
GUISetState(#SW_SHOW)
Local $hTimer = TimerInit()
While True
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Button1
$Go2 = True
HotKeySet("!{e}", "_Exit") ; Sets a shortcut to kill the script quickly. ESC
HotKeySet("{s}", "_ExitLoop") ; Sets a shortcut to kill the script quickly. ESC
Opt("WinTitleMatchMode", 3) ; This is to tell the script to only refresh the EXACT window, incase there are similar windows. Such as: Window 1, Window 2.
While $Go2 ; Avoid getting stuck in the while loop forever
If TimerDiff($hTimer) > 3000 Then
ConsoleWrite("Refreshing Mozilla" & #LF)
$title = WinGetTitle("Google - Mozilla Firefox", "") ; Grabs the exactly title and saves it to a variable to do an If statement against.
If WinExists($title) Then ; Check to see if the desired window is running.
WinActivate($title) ; If it is running, first activate the window.
WinWaitActive($title) ; This tells the script to not send the refresh key (F5) until the window has appeared.
Send("{F5}") ; This sends the F5 key to refresh the window.
$hTimer = TimerInit()
HotKeySet("{x}")
Else ; This is an else statement to tell the script to do a different operation if the window is not running.
;~ Sleep(10) ; Just a filler item to wait until the desired window is running.
EndIf ; End the If statement to continue the script.
EndIf
WEnd
$hTimer = TimerInit()
HotKeySet("{x}") ; Release hotkey
HotKeySet("!{e}") ; Release hotkeys
ConsoleWrite("Exited loop" & #LF)
Case $Button2
;you can't exit the loop from the $button1 here but there is a hotkey set to exit it, ALT + E
Send("{TAB}")
Send("^v")
EndSwitch
WEnd
Exit
Func _Exit()
Exit
EndFunc ;==>_Exit
Func _ExitLoop()
$Go2 = Not $Go2
EndFunc
P.S. I avoid using sleep because it pauses the script.
This is how I would do it.
Local $Refresh = 0 ; Set refresh OFF
Local $Timer = TimerInit()
Local $RefreshEvery = 3 ; seconds
Do
$msg = GUIGetMsg()
Select
Case $msg = $BtnRefresh
$Refresh = 1 ; Set refresh ON
Case $msg = $btnStop
$Refresh = 0 ; Set refresh OFF
EndSelect
If $Refresh And (TimerDiff($Timer) > $RefreshEvery*1000) Then
RefreshBrowser()
$Timer = TimerInit()
EndIf
Until $msg = $GUI_EVENT_CLOSE
Related
I have an assembly code for PIC18F458 that gets data from channel 0 (RA0) of ADC and displays the result on PORTC and PORTD.
Therefore, I am trying to stimulate the RA0 pin on a PIC18F458 using a SCL file in the MPLAB X V5.05 Stimulus window.
Although, the file is successfully attached (see Image 1); when I run the simulation, there is no way of confirming if the SCL is actually being ran, aside from the ADRESL and ADRESH regsiters not containing any values (see image 2).
Simulator Window without Run SCL button
No data in ADRESH and ADRESL registers
Additionally, I do not have a "Run SCL" button; unlike the other examples that I have seen online. (Please see image 1 above)
UPDATE:
Slightly modifying the examples provided by #Kozmotronik, I have been able to confirm that the SCL file is running and the injection of data onto the AIO pin. Therefore, this particular question can now be considered closed!!
After some research in SCL Code Repo and SCL User's guide that is provided within MPLAB IDE help, and also after some test, I couldn't manage to get values from a file even with a direct SCL code. The SCL code I used first is the following:
configuration for "pic18f458" is
end configuration;
testbench for "pic18f458" is
begin
// Register Injection
process is
file fileVar : text;
variable status : file_open_status;
variable val : integer;
begin
report("Analog injection started...");
file_open(status, fileVar, "<data_file_path>", read_mode);
if status == open_ok then
report("Reading the values file...");
while endfile(fileVar) == false loop
read(fileVar, val);
wait until ADCON0.GO_nDONE == '1';
report("Conversion started");
wait until ADCON0.GO_nDONE == '0';
report("Conversion ended");
if ADCON1.ADFM == '0' then -- left justified
ADRESH <= val / 4;
ADRESL <= val * 64;
else -- right justified
ADRESH <= val / 256;
ADRESL <= val;
end if;
end loop;
file_close(fileVar);
wait;
end if;
end process;
end testbench;
I did saw the report strings in the simulator output but the ADRES registers are always injected with 0xFFFF value. I tried modified versions with no success.
However, when I decided to modify the SCL code and give it a try with an in-code variable it did worked. The values of the in-code variable were injected correctly. From this case I figured out that the file read operation fails in somewhere and can't get the value from the file correctly. The latter working SCL code is the following:
configuration for "pic18f458" is
end configuration;
testbench for "pic18f458" is
begin
// Register Injection
process is
file fileVar : text;
variable status : file_open_status;
variable val : integer;
begin
report("Analog injection started...");
val := 7;
while val < 1024 loop
wait until ADCON0.GO_nDONE == '1';
report("Conversion started");
wait until ADCON0.GO_nDONE == '0';
report("Conversion ended");
if ADCON1.ADFM == '0' then -- left justified
ADRESH <= val / 4;
ADRESL <= val * 64;
else -- right justified
ADRESH <= val / 256;
ADRESL <= val;
end if;
val := val * 8;
end loop;
report("Analog injection ended...");
wait;
end process;
end testbench;
The above SCL code will inject the actual value of the val variable everytime an ADC conversion ends (GO_nDONE bit first goes high and when the conversion is completed goes low). The value injection is made depending on the ADFM bit. if it is set to 0 the value will be left justified, otherwise will be right justified.
So I have posted an issue in the microchip forums regarding this matter. Let's see how it will be resolved.
Well if the values need not to be very specific you can make use of the second SCL code. However, in order to enable register injection in MPLABX IDE you need to configure the simulator first. To do this
Open the project properties window by clicking File -> Project Properties in the menu.
Then from categories section select Simulator.
Select Periph: ADC1 from the Option categories in the right pane.
Finally make sure that Use MPLAB 8 Style Stimulus/SCL for ADCxBUF0 is checked as in the following image.
Once you've configured it open the stimulus window, first start the simulation once so that it shows its content and then click on Attach SCL file icon to attach your SCL file and finally restart the simulation with the newly attached SCL.
UPDATE
I just simplified this example from the SCL repository and boom it works!
What I change in the code is; I was reading from the text file directly into the SCL variable which gives me no success, with the help of the SCL repo example, I created a line variable called dline, I read from a file into the dline using readline() builtin function, then I read from dline into the val variable using the read() function which resulted with success. The ADRES registers did injected with the correct values by each reading. Here is the updated code:
end configuration;
testbench for "pic18f458" is
begin
// Register Injection
process is
file fileVar : text;
variable status : file_open_status;
variable dline : line;
variable val : integer;
begin
report("Analog injection started...");
file_open(status, fileVar, "<data_file_path>", read_mode);
if status == open_ok then
report("Reading the values file...");
while endfile(fileVar) == false loop
wait until ADCON0.GO_nDONE == '1';
readline(fileVar, dline);
read(dline, val);
report("Conversion started");
wait until ADCON0.GO_nDONE == '0';
report("Conversion ended");
if ADCON1.ADFM == '0' then -- left justified
ADRESH <= val / 4;
ADRESL <= val * 64;
else -- right justified
ADRESH <= val / 256;
ADRESL <= val;
end if;
end loop;
file_close(fileVar);
wait;
end if;
end process;
end testbench;
Here is the data file. Note that the values are separated with new lines:
1
3
7
15
31
63
127
255
511
755
927
1023
1015
988
775
550
285
137
79
47
24
12
5
1
I'm very new in AutoIt, worked before (a lot) with AutoHotkey.
Here is my attempt to slightly rewrite one of the scripts from AutoIt docs. The only part I've changed is the bottom one (Tab key).
What I want to achieve: If current window is Notepad, then send Ctrl-Tab instead of Tab. Otherwise, send normal Tab.
Well, I understand, why this code leads to recursion, but how I can avoid it?
#include <MsgBoxConstants.au3>
; Press Esc to terminate script, Pause/Break to "pause"
Global $g_bPaused = False
HotKeySet("{PAUSE}", "HotKeyPressed")
HotKeySet("{ESC}", "HotKeyPressed")
HotKeySet("{TAB}", "HotKeyPressed")
While 1
Sleep(100)
WEnd
Func HotKeyPressed()
Switch #HotKeyPressed
Case "{PAUSE}"
$g_bPaused = Not $g_bPaused
While $g_bPaused
Sleep(100)
ToolTip('Script is "Paused"', 0, 0)
WEnd
ToolTip("")
Case "{ESC}"
Exit
Case "{TAB}"
If WinActive("[CLASS:Notepad]") Then
Send("^{TAB}")
Else
Send("{TAB}")
EndIf
EndSwitch
EndFunc
Temporarily disable the hotkey:
Case "{TAB}"
HotKeySet("{TAB}") ;Cancel (or unregister) the hotkey
If WinActive("[CLASS:Notepad]") Then
Send("^{TAB}")
Else
Send("{TAB}")
EndIf
HotKeySet("{TAB}", "HotKeyPressed") ;re-enable hotkey
EndSwitch
I'm trying to make a function with hotkeys that pauses the script, so it doesn't send anything. But also a function that enables the script again. Here is what I have so far:
Func TogglePause()
$Paused = NOT $Paused
If $Paused Then ToolTip('Script "Paused"',500,500)
While $Paused
Sleep(1)
WEnd
ToolTip("")
EndFunc
Let's say you're typing H, the script pauses so it doesn't do anything. Once you press J the script is enabled again.
Directly from the helpfile (HotKeyset)
#include <MsgBoxConstants.au3>
; Press Esc to terminate script, Pause/Break to "pause"
Global $g_bPaused = False
HotKeySet("{PAUSE}", "TogglePause")
HotKeySet("{ESC}", "Terminate")
HotKeySet("+!d", "ShowMessage") ; Shift-Alt-d
While 1
Sleep(100)
WEnd
Func TogglePause()
$g_bPaused = Not $g_bPaused
While $g_bPaused
Sleep(100)
ToolTip('Script is "Paused"', 0, 0)
WEnd
ToolTip("")
EndFunc ;==>TogglePause
Func Terminate()
Exit
EndFunc ;==>Terminate
Func ShowMessage()
MsgBox($MB_SYSTEMMODAL, "", "This is a message.")
EndFunc ;==>ShowMessage
Does this fix your problem?
#include <MsgBoxConstants.au3>
; Press Esc to terminate script, Pause/Break to "pause"
Global $g_bPaused = False
HotKeySet("{PAUSE}", "HotKeyPressed")
HotKeySet("1", "HotKeyPressed")
HotKeySet("2", "HotKeyPressed")
HotKeySet("+!d", "HotKeyPressed") ; Shift-Alt-d
While 1
Sleep(100)
WEnd
Func HotKeyPressed()
Switch #HotKeyPressed ; The last hotkey pressed.
Case "{PAUSE}" ; String is the {PAUSE} hotkey.
$g_bPaused = Not $g_bPaused
While $g_bPaused
Sleep(100)
ToolTip('Script is "Paused"', 0, 0)
WEnd
ToolTip("")
Case "1"
While 1
Send('F')
Sleep(500)
WEnd
Case "2"
While 1
Send('D')
Sleep(500)
WEnd
Case "+!d" ; String is the Shift-Alt-d hotkey.
MsgBox($MB_SYSTEMMODAL, "", "This is a message.")
EndSwitch
EndFunc ;==>HotKeyPressed
I am revising the answer again to show my new example. This example will send "Q{ENTER}" at the start of the script every time the user hits the enter key. Now, when typing the letter 'b' on the keyboard, it automatically pauses the script and sends the key like normal. Whenever the user types the spacebar, the script is automatically activated again to start sending "Q{ENTER}" again. It can be manually paused/unpaused by using the pause/break key on the keyboard, and the process can be terminated by pressing the escape key.
Code.au3
; 1 - If the pause/break button is pressed, activate the togglePause function.
; 2 - If the esc (escape) key is pressed, stop the program.
; 3 - If the Enter key is pressed, run your function.
HotKeySet("{PAUSE}", "togglePause")
HotKeySet("{ESC}", "quitScript")
HotKeySet("{ENTER}","Enter")
; ADDED TWO HOTKEYS FOR B AND SPACE
HotKeySet("b", "keyPressB")
HotKeySet("{SPACE}", "keyPressSpace")
; This variable is set to leave the program unpaused at start.
global $isPaused = False
; This empty while loops keeps the program active until manually exiting.
While 1
WEnd
; This is a variation of the function you created.
Func Enter()
; If the program is unpaused (which it is at start), the program will send the Q then Enter button.
if $isPaused == false then
HotKeySet("{ENTER}");
Send("Q{ENTER}");
HotKeySet("{ENTER}","Enter")
; If the program is paused, it will send JUST the enter button like you are typing normally.
elseif $isPaused == true then
HotKeySet("{ENTER}");
Send("{ENTER}");
HotKeySet("{ENTER}","Enter")
EndIf
EndFunc
; ADDED THE TWO FUNCTIONS BELOW TO PROCESS THE B AND SPACE HOTKEYS
Func keyPressB ()
; Pauses the program
$isPaused = true
; Sends the b key like you are normally typing
HotKeySet("b")
Send("b")
HotKeySet("b", "keyPressB")
EndFunc
Func keyPressSpace ()
; Unpauses the program
$isPaused = false
HotKeySet("{space}")
Send("{SPACE}")
HotKeySet("{SPACE}", "keyPressSpace")
EndFunc
; Function to pause script
Func togglePause ()
; When this function is initiated, the code on the next line 'toggles' the variable to True/False. If the script is unpaused (the $isPaused variable is set to 'False') then the next line will change it to 'True' and vice versa.
$isPaused = NOT $isPaused
; Create a while loop to stall the program
; The line below is the same thing as "While $isPaused == True"
While $isPaused
; This code will run constantly until the $isPaused variable is set to 'True'. To make the script do nothing, simply add a sleep command.
Sleep(250)
WEnd
EndFunc
Func quitScript ()
Exit
EndFunc
Start - nothing happens.
Press f ==> script sends f until
a) you press d or ESC
a1) pressed d ==> script sends d until you press f or ESC
a2) pressed ESC ==> script pauses until you press
b1) d ==> sends D
b2) f ==> sends F
b3) ESC ==> sends the last letter sent before.
#include
; Press Esc to terminate script, Pause/Break to "pause"
Global $g_bPaused = False
HotKeySet("{ESC}", "HotKeyPressed")
HotKeySet("f", "HotKeyPressed")
HotKeySet("d", "HotKeyPressed")
HotKeySet("+!d", "HotKeyPressed") ; Shift-Alt-d
While 1
Sleep(100)
WEnd
Func HotKeyPressed()
Switch #HotKeyPressed ; The last hotkey pressed.
Case "{ESC}" ; String is the {PAUSE} hotkey.
$g_bPaused = Not $g_bPaused
While $g_bPaused
Sleep(100)
ToolTip('Script is "Paused"', 0, 0)
WEnd
ToolTip("")
Case "f"
$g_bPaused = False
While 1
Send('F')
Sleep(500)
WEnd
Case "d"
$g_bPaused = False
While 1
Send('D')
Sleep(500)
WEnd
Case "+!d" ; String is the Shift-Alt-d hotkey.
MsgBox($MB_SYSTEMMODAL, "", "This is a message.")
EndSwitch
EndFunc ;==>HotKeyPressed
I have one scenario problem and I don't want to use interrupts cause the same problem will be there I will be forced to use delay to insure that specific time did pass.
the problem:
I don't want to use the delay function cause it stops the other tasks to be checked or executed taking a situation:
I have motor that run 6 seconds if button1 is pressed and if a man press button2 the motor 2 immediately need to be turned on and work for 2 second.
so the code will be like this:
main ()
{
if( Rd0 == 0 ) // is button1 is pressed
{
RunMotre1();
__delay_ms(6000);
StopMotor1();
}
if( Rd1 == 0 ) // is button2 is pressed
{
RunMotor2();
__delay_ms(2000);
StopMotor2();
}
}
the problem of this code if we pressed the button b to start Motor 2 he will
not work cause the system is blocked on delay and wait it to be finished .
and that cause that if we start -> press button 1->motor 1 runing -> pressing buTTon2 to start Motor2-> Motor2 not working until the 6 seconds be passed.
so is there a way to resolve this problem case.
for example if exists comparing who mutch time Motor1 did run if is greate or = 6 secound then stop the motor 1 example (samthing like this if exist) :
Time counter1;
Time Counter2;
main()
{
if( Rd0 == 0 ) // is button 1 to start motor1 is presed ?
{
RunMotre1();
counter1.start();
}
if(counter1.CurentElapsedTimes==6 Secound) // is motor1 did run 6 seconds
{
counter1.stop();
counter1.Initialise();
StopMotor1();
}
if( Rd1 == 0 ) // is button 2 to start motor2 is pressed.
RunMotor2();
counter2.start();
}
if(counter2.CurentElapsedTimes==2 Secound) // is motor2 did run 2 seconds
{
counter2.stop();
counter2.Initialise();
StopMotor2();
}
or any solution
platform pic microcontroller using xc8 compiler
PRESUPPOSITION: I don't know which PIC you are using, but I assume that it has at least a free timer.
The problem here is that you need something to track the time as it passes. My suggestion is to use the same technique that the Arduino FW uses: setup a timer to fire an interrupt every X milliseconds/seconds, then in the interrupt service routine (ISR) update a counter.
When you press the button set the counter, then wait for the counter to reach another value before turning the motor off.
I'll write here a small pseudo-code example, since I don't remember how to properly write an ISR with a PIC compiler nor I know what is your PIC (and, so, the commands to initialize the timer).
I chose to use a timer granularity of 100ms, but you can change it as you prefer.
I also chose to set counter as a 8-bit variable; it can count up to 25.5 seconds, but since the highest delay is 6 seconds it's ok.
Note that you need just ONE timer, so you can add any number of motors without the need for adding counters
char counter;
char motor1StartTime;
char motor2StartTime;
bool motor1Running;
bool motor2Running;
Timer1_ISR()
{
counter++;
}
main()
{
counter = 0;
motor1StartTime = 0;
motor2StartTime = 0;
motor1Running = false;
motor2Running = false;
// Setup the timer to trigger the Timer1_ISR every 100ms
...
while(1)
{
if( Rd0 == 0 )
{ // If the button is pressed start the motor and save the counter
RunMotor1();
motor1StartTime = counter;
motor1Running = true;
}
if ((motor1Running) && ((counter - motor1StartTime) >= 60))
{ // If the motor is running from more than 6 seconds, shut it down
StopMotor1();
motor1Running = false;
}
if( Rd1 == 0 )
{ // If the button is pressed start the motor and save the counter
RunMotor2();
motor2StartTime = counter;
motor2Running = true;
}
if ((motor2Running) && ((counter - motor2StartTime) >= 20))
{ // If the motor is running from more than 2 seconds, shut it down
StopMotor2();
motor2Running = false;
}
}
}
I have an existing .exe program (not mine so I can't edit it) that runs in a window of static size. What I want to do is overlay an extra button (preferably an image in the same style) on top of this window at specific coordinates within that window (and it has to move with the window if dragged elsewhere) to expand on it's functionality.
How do I go about this? I have searched for quite a bit, but wasn't able to find anything. I was able to create a Parent-Child in AutoIT itself, but cannot seem to attach a child to an existing application.
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
; NotepadAddOn
ShellExecute('notepad')
WinWaitActive("[CLASS:Notepad]", "")
$pos_A = WinGetPos("[CLASS:Notepad]", "")
$hGui = GUICreate('YOUR GUI', $pos_A[2], 50, $pos_A[0], $pos_A[1] - 50)
GUISetState(#SW_SHOW) ; will display an empty dialog box
AdlibRegister('_WinMove', 10)
; Run the GUI until the dialog is closed
While 1
$msg = GUIGetMsg()
If $msg = $GUI_EVENT_CLOSE Then ExitLoop
WEnd
GUIDelete()
Func _WinMove()
$p_A = WinGetPos("[CLASS:Notepad]", "")
WinMove($hGui, "", $p_A[0], $p_A[1] + $p_A[3])
EndFunc ;==>_WinMove