User Tools

Site Tools


useful_programs

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
useful_programs [2019/06/20 11:20] – [Detecting rise / fall edge of the signals] emozolyakuseful_programs [2020/06/03 12:00] – [Other handy functions] emozolyak
Line 22: Line 22:
 To access idividual bits, you can use following handy functions: To access idividual bits, you can use following handy functions:
 <code lua> <code lua>
--- to check, set,clear individual bits in numbers 
 function bw(n) function bw(n)
   return 2 ^ (n - 1)  -- returns weight of the bit in pos. n   return 2 ^ (n - 1)  -- returns weight of the bit in pos. n
 end end
- +  
-function hasbit(x, p) +function hasbit(x, b)  
-  return x % (p + p) >= p  -- returns if is true/false; if hasbit(value, bw(2)) then ...+  local = bw(b
 +  return x % (p + p) >= p  -- returns if is true/false; if hasbit(value, b) then ...
 end end
- +  
-function setbit(x, p+function setbit(x, b)  
-  return hasbit(x, p) and x or x + -- sets bit #p in х example:  х = setbit(х, bit(p))+  return hasbit(x, b) and x or x + bw(b) -- sets bit in х example:  х = setbit(х, b))
 end end
- +  
-function clearbit(x, p+function clearbit(x, b
-  return hasbit(x, p) and x - or x --  clears bit #p in х +  return hasbit(x, b) and x - bw(b) or x --  clears bit in х 
 end end
- +  
-function togglebit(x, b) -- toggles bit #b in x  +function togglebit(x, b) -- toggles bit b in x  
-    local r  +    if hasbit(x, b) then  
-     +        return clearbit(x, b)
-    if hasbit(x,bw(b)) then  +
-        r = clearbit(x, bw(b))+
     else      else 
-        r = setbit(x, bw(b))+        return setbit(x, b)
     end      end 
-    return r  
 end  end 
- +  
--- output bool conditoin as 0 /1 into a bit  +function outbit(condition, x, b) -- output bool condition as 0 /1 into a bit  
-function outbit(x, p, condition) +     if condition then      
-     if condition   then      +         return hasbit(x, b) and x or x + bw(b
-         return hasbit(x, p) and x or x + p -- sets bit #p in х example:  х = setbit(х, bw(p))+
      else       else 
-         return hasbit(x, p) and x - or x --  clears bit #p in х      +         return hasbit(x, b) and x - bw(b) or x 
      end       end 
 end  end 
  
--- uses alias and sets bit in it  +function outBit(condition, alias, b) -- output bool condition as 0 /1 into a bit of a internal register  
-function setBit(alias, b) +     local new_value outbit(condition, R(alias), b) 
-    local value = R(alias) +     W(alias, new_value)
-    value = setbit(valuebw(b)+
-    W(alias, value)+
 end  end 
 + 
 +function setBit(alias, b) -- sets bit in the register using alias or id   
 +    local old_value = R(alias) 
 +    local new_value = setbit(old_value, b) 
  
--- uses alias and crears bit in it  +    if (new_value ~= old_valuethen  
-function clearBit(alias, b+        WriteReg(alias, new_value -- to prevent unnecessary writing 
-    local value = R(alias+    end 
-    value = clearbit(valuebw(b)+
-    W(alias, value)+
 end  end 
  
 +function clearBit(alias, b) -- uses alias or id and crears bit in it 
 +    
 +    local old_value = R(alias)
 +    local new_value = clearbit(old_value, b)
 +    
 +    if (new_value ~= old_value) then 
 +        WriteReg(alias, new_value)
 +    end 
 +end 
 +
 +function toggleBit(alias, b) -- toggles bit b in reg by alias or id 
 +     local cur_value = R(alias)
 +    
 +    if hasbit(cur_value, b) then 
 +        clearBit(alias, b)
 +    else 
 +        setBit(alias, b)
 +    end 
 +    return true 
 +end 
 + 
 -- return bit from the position as a  1 / 0  -- return bit from the position as a  1 / 0 
-function getBit(xp+function getBit(aliasb) 
-    if hasbit ( p) then +     
 +    if hasbit(R(alias)b) then 
         return 1          return 1 
     else      else 
Line 122: Line 140:
  
 <code lua> <code lua>
-function DBG ( ... ) +function DBG(...) 
-            -- ... means variable number of arguments in luapassed in the 'argtable +local tc = tabToStr 
- +  
-if ENABLE_DEBUG then -- should be global in the calling script +function align2s(s1, s2) -- appends space to smaller string  
 +    local d, s = (#s1 - #s2), ' ' ; local ad = math.abs(d)
          
-    local s ""            -- string buffer to concatenate all arguments +    if (d ~0) then  
-        for i #arg do  +         
-        -- glue all and add spaces, use tostring to protect from nil argument  +        local Lp, Rp 00 
-            = s .. tostring arg [i]  ) .. ' ' +         
 +        if ((ad % 2) == 0) then  
 +            Lp ad / 2 ; Rp = Lp ; INFO("even parts, L R = " .. Lp .. s .. Rp) 
 +        else  
 +            Lp = math.floor(ad / 2; Rp = Lp + 1 ; INFO("not even L R " .. Lp .. s .. Rp)
         end          end 
-    DEBUG ( s ) +        return (((d > 0) and {s1, s:rep(Lp) .. s2 .. s:rep(Rp)})  
-end -- if +                        or 
 +             ({s:rep(Lp) .. s1 .. s:rep(Rp), s2})) 
 +    else  
 +        return {s1, s2} 
 +    end  
 +end  
 + 
 +    if ENABLE_DEBUG then  
 +        local arg_str = tc(arg) 
 +        local t_s_pos = string.find(arg_str, "|")  
 +  
 +        if not t_s_pos then  
 +            INFO(arg_str)  -- Just printing single line  
 +        else  
 +            local h_row, v_row = {}, {}  
 +            -- header  
 +            for w in string.gmatch(arg[1], "%S+") do 
 +                h_row[#h_row + 1] = w       
 +            end  
 +            -- values  
 +            for i = 3, #arg do  
 +                v_row[#v_row + 1] = tostring(arg[i]) 
 +            end  
 +  
 +            if (#h_row ~= #v_row) then  
 +                ERROR("Inconsistent header and value rows in DBG!"
 +                INFO("h_row:" .. tc(h_row)) ; INFO("v_row" .. tc("v_row")) 
 +                return  
 +            else  
 +                for g = 1, #h_row do  
 +                    h_row[g], v_row[g] = unpack(align2s(h_row[g], v_row[g])) 
 +                end  
 +            end  
 +            INFO(tc(h_row)) ; INFO(tc(v_row)) 
 +        end     
 +    end  
 +end   
 +  
 +function tabToStr(t)  -- glue all and add spaces, use tostring to protect from nil and bool argument  
 +    local s = ""             
 +    for i = 1, #t do  
 +        local e = t[i] ; if (e == nil) then e = 'nil' end  
 +        s = s .. tostring(e) .. ' '  
 +    end -- for  
 +    return s  
 +end
  
-end -- DBG  
 </code> </code>
 +Then the print output can be enhanced like this:
 +{{ :dbg_table_out.png?direct&600 |}}
  
 The //ENABLE_DEBUG// flag should be global boolean variable in the calling script. You may just to set it when needed and save the script.  The //ENABLE_DEBUG// flag should be global boolean variable in the calling script. You may just to set it when needed and save the script. 
Line 159: Line 228:
   end    end 
  
 +</code>
 +
 +For complex tables print, you can use the following function:
 +<code lua>
 +function tprint(t, indent)
 +    if not indent then indent = 0 end 
 +    for k, v in pairs(t) do 
 +        local formatting = string.rep(' ', indent) .. k .. ': '
 +        if type(v) == "table" then 
 +            ERROR(formatting) 
 +            tprint(v, indent + 1) -- recursive call 
 +        else
 +            if type(v) == "boolean" then 
 +                v = v and "TRUE" or "FALSE"
 +            end 
 +            ERROR(formatting .. v) 
 +        end 
 +    end -- for 
 +end -- tprint 
 </code> </code>
  
Line 210: Line 298:
  
 <code lua> <code lua>
- function Timer (bool_input, onDelay, offDelay, tmrAlias)+function Timer (bool_input, onDelay, offDelay, tmrAlias)
 --                bool      sec to ON  sec to OFF  string alias --                bool      sec to ON  sec to OFF  string alias
 + 
 +local now , nowString, curTimeStamp, curTmrState =  
 +os.time(), os.date("%c", now), R(tmrAlias), TRUE(tmrAlias .."_out"    
  
-local now , nowString, curTimeStamp, curTmrState =  os.time() +    DBG("Timer State Stamp", "|", tmrAlias, curTmrState, os.date("%c", curTimeStamp)) 
-                                                    os.date("%c", now),  +
-                                                    R(tmrAlias), +
-                                                    TRUE(tmrAlias .."_out"     +
-                                           +
-DEBUG("curTimeStamp - ", os.date("%c", curTimeStamp) ) +
-DEBUG ("cur "..tmrAlias.." State =  "..tostring(curTmrState))                  +
 -- protects from malfunctions on very first run  -- protects from malfunctions on very first run 
 if curTimeStamp == 0 then  if curTimeStamp == 0 then 
-    DEBUG("curTimeStamp was zero in this timer!")+    DBG("curTimeStamp was zero in this timer!")
     WriteReg(tmrAlias, now)     WriteReg(tmrAlias, now)
     return nil, 0 -- countdown      return nil, 0 -- countdown 
 end  end 
 + 
     -- in and output are equal                                                          -- in and output are equal                                                     
-    if (bool_input == curTmrState) then  + 
-        WriteReg(tmrAlias, now)                           DEBUG("timer input match state "+if (bool_input == curTmrState) then  
 +        WriteReg(tmrAlias, now) ; DBG("timer inputs match"
         return curTmrState, 0   -- as bool          return curTmrState, 0   -- as bool 
-     +         
-    -- TON      +                            -- TON      
-    elseif bool_input then  +elseif bool_input then  
-         if ((now - GetReg(tmrAlias)) > onDelay) then  +         if ((now - curTimeStamp) > onDelay) then  
-             WriteReg(tmrAlias .."_out", 1 +             SET(tmrAlias .."_out") ; WriteReg(tmrAliasnow; DBG("detected ON state after delay")
-                                                        DEBUG("detected ON state after delay (input, now, tmr, onDelay ):", bool_input, nowString, onDelay)+
              return true, 0                return true, 0  
         else          else 
-            local countDown = onDelay - (now - curTimeStamp) +            local countDown = onDelay - (now - curTimeStamp) ; DBG("countdown to On in "countDown)
-            DEBUG("countdown to On in " .. tmrAlias .. " ".. countDown)+
             return curTmrState, countDown             return curTmrState, countDown
         end          end 
 + 
 +                            -- TOFF     
 +elseif not bool_input then 
          
-    -- TOFF      +        if ((now - curTimeStamp) > offDelay) then    
-    elseif not bool_input then  +            RESET(tmrAlias .."_out") ; WriteReg (tmrAliasnow; DBG("detected OFF state after delay"
-        if (now - GetReg ( tmrAlias ) > offDelay) then    +            return false, 0   
-            WriteReg (tmrAlias .."_out", 0) +
-            DEBUG("detected OFF state after delay (input, now, tmr, offDelay ):", bool_input, nowString, offDelay+
-            return false  +
         else          else 
-            local countDown = offDelay - (now - curTimeStamp) +            local countDown = offDelay - (now - curTimeStamp) ; DBG("countdown to OFF in "countDown)
-            DEBUG ("countdown to OFF in " .. tmrAlias .." ".. countDown)+
             return curTmrState, countDown             return curTmrState, countDown
         end          end 
Line 545: Line 627:
 To determine intermediate positions, a calculated value is used, determined from the characteristics of the 'full path time', which can also be determined experimentally.   To determine intermediate positions, a calculated value is used, determined from the characteristics of the 'full path time', which can also be determined experimentally.  
  
-Below is a variant of 3-point control for a valve with 2 limit switches. +Below is a variant of 3-point control for a valve withoutlimit switches. 
  
 <code lua> <code lua>
-function main (userId)+function valveControl(v) 
 +     
 +    local FULL_PATH_TIME = R(v .. "pathTime") ; local KOEF = 100 / FULL_PATH_TIME 
 +    local HOMING_DELAY = R(v .. "homingDelay") * 60 * 60 -- get seconds from hours  
          
-       -- copy desired Tfeed to valve PID target temp. +    local auto, autoOpenCmd, autoCloseCmd, now =  
-    ( "HeatDistribution.targetTemperature",  ( "recalcFeedTemp" ))     +          TRUE("auto_mode"), TRUE(v .. "openCmd")TRUE(v .. "closeCmd"), os.time() 
 +                     
 +local motionTmr = function() -- calc. path quant passed from last call 
  
-now = os.time() -- global +    local quant = 0 
 +    if (autoOpenCmd or autoCloseCmd) then  
 +          quant = (now - R(v .. "motionTmr")) * KOEF ; SET(v .. "valveStatus") -- opening  
 +           
 +          if autoCloseCmd  then   
 +              quant quant * (-1)          -- closing  
 +              UpdReg(v .. "valveStatus", 2)  
 +          end  
 +    else  
 +          RESET(v .. "valveStatus") 
 +          quant = 0  
 +    end  -- if motion  
 +    UpdReg(v .. "motionTmr", now)     -- remember last call  
 +    return quant 
 +end -- motionTmr 
  
-local manOpenCmd, manCloseCmd = R("manOpenCmd"), R("manCloseCmd"    -- manual run flags +    local pos Limiter(Round(R(v .. "curPosition")) + motionTmr(), 0, 100) 
-local autoOpenCmd, autoCloseCmd R("autoOpenCmd"), R("autoCloseCmd") -- cmds to control valve +    local sp = R(.. "posSetpoint" 
-local openSw, closeSw = (R("valveOpenSw"== 1) , (R("valveCloseSw") == 1) +
-local pullUpFlag, pullDownFlag = (R("pullUpFlag") == 1 ), (R("pullDownFlag") == 1 )  ;  +
- +
-local curPosition = Round(R("valveCurPos") + MotionTimer(autoOpenCmd, autoCloseCmd, "Tmr5")) ; DEBUG("curPosition calc. as "..curPosition) +
- +
-                -- filtering cur position and check limit sw +
-if (curPosition >= 100) or openSw then  +
-    curPosition = 100  +
-        if openSw then  +
-            W ("pullUpFlag"1 ) +
-            pullUpFlag = true  +
-        end  +
-end  +
- +
-if ((curPosition < 0) or closeSw) then  +
-    curPosition = 0  +
-        if closeSw then  +
-            W ("pullDownFlag"1 )  +
-            pullDownFlag = true  +
-        end  +
-end  +
-                            -- pulling +
-if (curPosition == 100) and not (openSw) and not pullUpFlag then  +
-    curPosition = 99  ;                                             DEBUG(" pulling up")  +
-end  +
-if (curPosition == 0 ) and not (closeSw) and not pullDownFlag then  +
-    curPosition = 1   ;                                             DEBUG(" pulling down")  +
-end  +
- +
-W ("valveCurPos", curPosition) -- renew current position +
- +
-                                    -- AUTO MODE ----  +
-local valveSp = R ( "valveSp" )  ;                                     DEBUG("valveSp  "..valveSp)                                      +
-local positionError = (curPosition - valveSp)    +
- +
-if (positionError ~= 0) and ( autoOpenCmd ~= 1) and (autoCloseCmd ~= 1) then  +
-    -- reset pulling flags befor start  +
-    W ("pullDownFlag, 0 ); W ("pullUpFlag", 0) +
-end  +
- +
-if ( R ( "distribAutoMode") == 1) then +
          
-    W ("manOpenCmd"0 ) -- clear manual cmds +    local uShootoShoot = (pos < sp)(pos > sp
-    W ("manCloseCmd"0    +
          
-    if (positionError == 0)  then  +    local homingOut TRUE(v .. "homingTmr_out") 
-        W ("autoOpenCmd", 0 ) +    local homing Timer(not homingOut, HOMING_DELAY, FULL_PATH_TIME * 2, v .. "homingTmr") 
-        W ("autoCloseCmd", 0)  +    if not homingOut and homing then  
-    elseif (positionError > 0)   then  +        AddInfoMessage("Started homing for valve " .. v)
-                                    DEBUG("GO DOWN because positionError "..positionError) ; DEBUG(" math.abs error <= 0."..math.abs(positionError)) +
-        W ("autoOpenCmd",) +
-        W ("autoCloseCmd", 1) -- GO DOWN +
-         +
-    elseif (positionError < 0)  then  +
-                                    DEBUG("GO UP because positionError = "..positionError) ; DEBUG(" math.abs error <= 0.5 "..math.abs(positionError)) +
-        W ("autoOpenCmd", 1 ) -- GO UP +
-        W ("autoCloseCmd", 0)  +
-    else  +
-                                    DEBUG("Undefined if !!! in valve control ")+
     end      end 
-                                  --- MANUAL MODE -----  
-else                 
-                                  -- just copy manual cmd to valve auto cmd 
-    W ("autoOpenCmd", manOpenCmd ) 
-    W ("autoCloseCmd", manCloseCmd) 
          
-     if not openSw then  +    OUT(auto and uShoot and not homing or (not auto and TRUE(v .. "manOpenCmd")), v .. "openCmd") 
-        W ("autoOpenCmd", manOpenCmd )  +    OUT(auto and oShoot or homing or (not auto and TRUE(.. "manCloseCmd")) .. "closeCmd") 
-    else  +    UpdReg(.. "curPosition", pos)
-        W ("manOpenCmd", 0 ) +
-        W ("autoOpenCmd",) +
-        W ("valveCurPos"100) -- renew position after open limit sw +
-    end  +
-    if not closeSw then  +
-        W ("autoCloseCmd", manCloseCmd)  +
-    else  +
-        W ("manCloseCmd", 0)  +
-        W ("autoCloseCmd", 0)  +
-        W ("valveCurPos", 0) -- renew position after close limit sw +
-    end  +
-    +
-end  +
- +
-end -- main  +
- +
-function MotionTimer(openCmd, downCmd, tmrAlias) +
- +
-local FULL_PATH_TIME = 180 -- sec. full path time +
-local KOEF = 100 / FULL_PATH_TIME +
-local quant = 0  +
---[[                 bool        string  +
-remembers start time +
-recalc. micro path from the previous call if was in motion +
-adds micro path to current position  +
---                                                  open = true                                       ]]  +
-    local motion = { flag = ((openCmd == 1) or (downCmd == 1)), dir = (openCmd == 1), lastTimeStamp = R(tmrAlias)} +
-    DEBUG(" motion.flag = "..tostring(motion.flag).." dir  "..tostring(motion.dir)..os.date("%c"lastTimeStamp))  +
-    local outAlias = tmrAlias.."_out" +
-    local curTmrState = (R(outAlias) == 1) ; DEBUG("cur "..tmrAlias.." State =  "..tostring(curTmrState)) +
-                                                 +
-    if motion.flag then  +
-      quant = (now - R(tmrAlias)) * KOEF +
-          if not motion.dir then  +
-              quant = quant * (-1)  +
-          end  +
-                                                     DEBUG("quant calculated as = "..quant) +
-      W (outAlias, 1) -- "in motionflag +
-                                                     +
-    else  +
-                    DEBUG("no motion lasts = ") +
-      W (outAlias0  +
-      quant = 0  +
-    end  -- if +
          
-(tmrAliasnow)     -- rememeber last call time  +    DBG("auto sp pos autoOpenCmd autoCloseCmd uShoot oShoot ", '|',  
-return quant +           auto, sp, Round(pos, 1), autoOpenCmd, autoCloseCmd, uShoot, oShoot) 
- +end
-end -- function +
 </code> </code>
  
Line 770: Line 769:
             return false -- nothing happened              return false -- nothing happened 
 end -- P_TRIG  end -- P_TRIG 
 +
 +function MulGetReg(...) -- multiple ids or aliases read, returns table, have to be unpack() 'ed
 +     local results = {} 
 +     for i = 1, #arg do 
 +         local param = arg[i]
 +        --  INFO("processing " .. param .. " paramter")
 +          results[i] = GetReg(param)
 +     end 
 +     if (#results == 1) then 
 +         return results[1]
 +     else 
 +         return results
 +     end 
 +end 
 </code> </code>
  
useful_programs.txt · Last modified: 2024/05/27 13:23 by emozolyak

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki