this procedure of 1 of items of status bar on i3 window manager on linux. run every second. deals frequency governors. if temperature reaches number switch powersave mode, or if application running, e.g. steam, or laptop running on batteries. if temperature reaches lower point switch performance, etc.
the procedure runs far, no issues. code has many nested if-else statements, hard maintain , everytime add code becomes more, well.... nested.
proc cpu_freq {} { set app steam set cpu_power [exec sudo cpupower frequency-info | sed -ne /speed/p] set cpu_temp [exec sensors | grep core | sed -n {2p} | awk {{print $3}} | cut -c2-3] set battery [exec acpi] if {[string match *performance* $cpu_power]} {set cpu_freq high; set color "$::green"} if {[string match *powersave* $cpu_power]} {set cpu_freq low; set color "$::red"} if {![file isfile $::i3dir/powersave.freq] && ![file isfile $::i3dir/performance.freq]} { set switch auto } # on battery if {[string match *discharging* $battery]} { # when in performance mode if {[string match *performance* $cpu_power]} { if {![file isfile $::i3dir/performance.freq]} { # , not in manual # switch powersave exec sudo cpupower frequency-set -g powersave set cpu_freq low set switch auto set color "$::red" set ::on_battery true } else { # switch manual performance mode if {[file isfile $::i3dir/performance.freq]} { exec sudo cpupower frequency-set -g performance set cpu_freq high set switch man set color "$::green" set ::on_battery true } else { if {[file isfile $::i3dir/powersave.freq]} { # switch manual powersave mode exec sudo cpupower frequency-set -g powersave set cpu_freq low set switch man set color "$::red" set ::on_battery true } } } } else { # when in powersave mode (auto) # switch manual powersave if {[string match *powersave* $cpu_power]} { if {[file isfile $::i3dir/powersave.freq]} { exec sudo cpupower frequency-set -g powersave set cpu_freq low set switch man set color "$::red" set ::on_battery true } else { # switch manual performance if {[file isfile $::i3dir/performance.freq]} { exec sudo cpupower frequency-set -g performance set cpu_freq high set switch man set color "$::green" set ::on_battery true } } } } # on mains } else { # when in powersave mode if {[string match *powersave* $cpu_power]} { # running app or manual switch if {[file isfile $::i3dir/powersave.freq]} { set cpu_freq low set switch man } else { if {[isrunning $app]} { set cpu_freq low set switch auto # nothing, keep running in powersave mode } else { # switch performance after running on batteries if {$::on_battery==true} { exec sudo cpupower frequency-set -g performance set cpu_freq high set switch auto set color "$::green" set ::on_battery false # switch performance when reaching lower temps } elseif {$cpu_temp <= 55} { exec sudo cpupower frequency-set -g performance set cpu_freq high set switch auto set color "$::green" } } } # when in performance mode } else { # manual switch if {[file isfile $::i3dir/performance.freq]} { set switch man set cpu_freq high # nothing, keep running in performance mode } else { # hot temperature or running app # switch powersave if {$cpu_temp >= 75 || [isrunning $app] } { exec sudo cpupower frequency-set -g powersave set cpu_freq low set switch auto set color "$::red" } else { set cpu_freq high set switch auto } } } } set stdout {{"name":"cpu_freq","full_text":"$switch:$cpu_freq","color":"$color"}} set stdout [subst -nocommands $stdout] puts -nonewline $stdout }
when see think finite state machines/state transition diagrams. have starting state , switch other states based on results of procs call in if statements, @ point reach end state no further transitions possible.
so i'd @ restructuring following example:
# value process set value "this big red ball" # starting state set state 1 # state transtions , functions implement them set states [dict create "1,3" "isred" "1,2" "isblue" "2,4" "isbig" "2,5" "issmall" "3,4" "isbig" "3,5" "issmall"] # procs implement state transitions proc isred {next} { global value state if {[string first "red" $value] != -1} { puts "red" set state $next return true } return false } proc isblue {next} { global value state if {[string first "blue" $value] != -1} { puts "blue" set state $next return true } return false } proc issmall {next} { global value state if {[string first "small" $value] != -1} { puts "small" set state $next return true } return false } proc isbig {next} { global value state if {[string first "big" $value] != -1} { puts "big" set state $next return true } return false } # proc run state machine until state stops changing proc runmachine { states } { global state set startstate -1 while { $state != $startstate } { set startstate $state foreach key [dict keys $states "$state,*"] { set next [lindex [split $key ","] 1] set res [[dict $states $key] $next] # if state changes no need more processing if { $res == true } { break } } } } runmachine $states
this 1 possible approach , it's simpler need shows basic idea. dictionary shows allowed state transitions , proc run in order test if transition allowed. i've put processing code (the puts statement) in function simple have function processing, either called directly or held value in dictionary , called runmachine proc.
set states [dict create 21,3" [list "isred" "redaction"]]
this approach lets seperate actions , transitions out , draw state transition diagram shows what's going on.
a quick google tcl finite state machine shows lots of other ways implement idea.
Comments
Post a Comment