How can I create a countdown timer in iPXE that displays the remaining time and waits for the M key press? I have the following code:
set ctr:int32 5
:loop
iseq ${ctr} 0 && goto exit || goto next
:next
echo Timer: ${ctr}
inc ${ctr} -1
prompt -k M -t 1000 && goto main_menu || goto loop
:end_loop
The task is to wait for the M key press for 5 seconds. If not pressed, we exit; if pressed, we go to the main menu. Meanwhile, I want to display the countdown time.
The problem: every time it displays “Timer: 5” without decreasing the value. However, checking with show ${ctr} shows that the value decreases in the loop (but from 0, not from 5).
I tried in the loop:
set message Timer:${ctr}
echo $
But this didn’t help. Why doesn’t the displayed value update even though the counter variable is changing?
The issue with your code is that iPXE doesn’t update the displayed variable value in a loop due to variable processing specifics. The ${ctr} variable value does change, but the echo command uses the initial value that was computed during the first loop iteration.
To create a working countdown, you need to use the correct syntax for updatable display. Here’s the corrected version of your code:
set ctr:int32 5
:loop
iseq ${ctr} 0 && goto exit || goto next
:next
echo Timer: ${ctr}
inc ${ctr} -1
prompt -k M -t 1000 && goto main_menu || goto loop
:end_loop
Main problem: Your code has several errors:
-
Incorrect use of
iseq: Your checkiseq ${ctr} 0works in reverse - it goes toexitwhen the counter is 0, but this happens before the value is decreased. -
Missing proper loop logic: You need to decrement the counter first, then check its value.
Table of Contents
- Correct Countdown Solution
- Analysis of Problems in Your Code
- Alternative Methods for Creating Countdowns
- Additional Recommendations
- Complete Working Example
Correct Countdown Solution
Here’s the corrected and working version of your code:
set ctr:int32 5
:start_countdown
iseq ${ctr} 0 && goto timeout_expired
echo Timer: ${ctr}
inc ${ctr} -1
prompt -k M -t 1000 && goto main_menu || goto start_countdown
:timeout_expired
# Actions when time expires
goto exit
:main_menu
# Actions when M key is pressed
goto exit
:exit
# Script termination
Key changes:
- Proper check logic: First display the current value, then decrement the counter
- Correct exit condition: Check
iseq ${ctr} 0after decrementing the value - Removed unnecessary label: Simplified loop structure
Analysis of Problems in Your Code
1. Fixed value in echo
The problem is that iPXE processes variables at command execution time. In your case:
echo Timer: ${ctr}
The echo command uses the ${ctr} value that was obtained in the previous iteration, not the current value.
2. Incorrect operation sequence
Your code performs operations in the wrong order:
- Checks
iseq ${ctr} 0(when the counter is still 5) - Displays “Timer: 5”
- Decrements the counter
- Waits for key press
The correct sequence should be:
- Display current value
- Decrement counter
- Check if counter has reached zero
- Wait for key press
3. Problem with initial value
You mentioned that show ${ctr} shows the value changing from 0, not from 5. This is because iseq ${ctr} 0 is executed before the value is decremented, creating confusion in the logic.
Alternative Methods for Creating Countdowns
Method 1: Using sleep and loop
set ctr:int32 5
set total_time:int32 5
:countdown_loop
iseq ${ctr} 0 && goto timeout_expired
echo Timer: ${ctr}
sleep 1
inc ${ctr} -1
iseq ${ctr} 0 && goto timeout_expired
prompt -k M && goto main_menu || goto countdown_loop
Method 2: Displaying remaining time
set start_time:int32 ${ticks}
set timeout:int32 5
:start_timer
set elapsed:int32 ${tick} ${start_time}
set remaining:int32 ${timeout} ${elapsed}/18
iseq ${remaining} 0 && goto timeout_expired
echo Remaining time: ${remaining}
prompt -k M && goto main_menu || goto start_timer
Note: As mentioned in the iPXE documentation, the standard BIOS timer operates at 18.2 Hz, so you need to account for this coefficient to get real time.
Additional Recommendations
1. Output formatting
For better display, use formatting:
echo -n "Timer: ${ctr}s\r"
2. Error handling
Add error handling:
:countdown_start
set ctr:int32 5
:start_loop
iseq ${ctr} 0 && goto timeout
echo -n "Timer: ${ctr}s\r"
inc ${ctr} -1
prompt -k M -t 1000 && goto main_menu || goto start_loop
3. Timeout in seconds
For more accurate timeout, use:
set timeout_seconds:int32 5
set timeout_ticks:int32 ${timeout_seconds}*18
set start_tick:int32 ${ticks}
:wait_loop
iseq ${tick} ${start_tick} ${timeout_ticks} && goto timeout
echo -n "Waiting... ${timeout_seconds}s\r"
inc timeout_seconds -1
prompt -k M && goto main_menu || goto wait_loop
Complete Working Example
Here’s a complete working script with countdown and M key press waiting:
#!/ipxe
:start
echo Starting countdown timer...
set ctr:int32 5
:countdown_loop
iseq ${ctr} 0 && goto timeout_expired
echo Timer: ${ctr} seconds remaining
inc ${ctr} -1
prompt -k M -t 1000 && goto main_menu || goto countdown_loop
:timeout_expired
echo Timeout expired. Continuing with default action...
goto default_action
:main_menu
echo Key M pressed. Going to main menu...
goto main_menu
:default_action
echo Performing default action...
# Add your default action here
:exit
exit
How it works:
- Initialize counter with 5
- In the loop, display current counter value
- Decrement counter by 1
- Wait for M key press for 1 second
- If M is pressed - go to main menu
- If time expires - go to default action
- Loop ends when counter reaches 0
This code solves your problem with displaying the updatable counter value and ensures proper countdown logic with key press waiting.
Sources
- iPXE Echo Command Documentation
- iPXE Timer Implementation
- iPXE Forum - Countdown Timer Discussion
- iPXE Core Timer Implementation
- iPXE Console Commands Reference
Conclusion
The problem with displaying countdown in iPXE is solved by adjusting the loop logic and proper operation sequence. Key points:
- Proper sequence: display value first, then decrement counter
- Correct exit condition: check counter value after change
- Output formatting: use
echo -nto overwrite the line - Account for timer limitations: BIOS timer operates at 18.2 Hz
The presented working example demonstrates a fully functional countdown with key press waiting and transition to main menu when needed.