tmr.stop(0)--SAFETRIM
-- function _doTick(self)

  -- Upvals
  local self                = ...
  local wifi,net            = wifi,net
  local sta                 = wifi.sta
  local config,log,startApp = self.config,self.log,self.startApp
  local tick_count          = 0

  local function socket_close(socket) --upval: self, startApp
    if rawget(self,"socket") then
      self.socket=nil                        -- remove circular reference in upval
      pcall(socket.close,socket)
      return startApp("Unexpected socket close")
    end
  end

  local function receiveFirstRec(socket, rec)  -- upval: self, crypto, startApp, tmr
    local cmdlen   = (rec:find('\n',1, true) or 0) - 1
    local cmd,hash = rec:sub(1,cmdlen-6), rec:sub(cmdlen-5,cmdlen)
    if cmd:find('"r":"OK!"',1,true) or cmdlen < 16 or
      hash ~= crypto.toHex(crypto.hmac("MD5", cmd, self.secret):sub(-3)) then
      print "No provisioning changes required"
      self.socket = nil
      self.post(function()  --upval: socket
                  if socket then pcall(socket.close, socket) end
                end)
      return startApp("OK! No further updates needed")
    end
    -- Else a valid request has been received from the provision service free up
    -- some resources that are no longer needed and set backstop timer for general
    -- timeout.  This also dereferences the previous doTick cb so it can now be GCed.
    collectgarbage()
    tmr.alarm(0, 30000, tmr.ALARM_SINGLE, self.startApp)
    return self:_provision(socket,rec)
  end

  local function socket_connect(socket) --upval: self, socket_connect
    print "Connected to provisioning service"
    self.socket = socket
    socket_connect = nil                  -- make this function available for GC
    socket:on("receive", receiveFirstRec)
    return self.socket_send(socket, self.config)
  end

  local conn
  return function() -- the proper doTick() timer callback
    tick_count = tick_count + 1
    log("entering tick", tick_count, sta.getconfig(false), sta.getip())
    if (tick_count < 20) then             -- (wait up to 10 secs for Wifi connection)
      local status, ip = sta.status(),{sta.getip()}
      if (status == wifi.STA_GOTIP) then
        log("Connected:", unpack(ip))
        if (config.nsserver) then
          net.dns.setdnsserver(config.nsserver, 0)
        end
        conn = net.createConnection(net.TCP, 0)
        conn:on("connection",     socket_connect)
        conn:on("disconnection",  socket_close)
        conn:connect(config.port, config.server)

        tick_count = 20
      end

    elseif (tick_count == 20) then        -- assume timeout and exec app CB
      return self.startApp("OK: Timeout on waiting for wifi station setup")

    elseif (tick_count == 26) then        -- wait up to 2.5 secs for TCP response
      tmr.unregister(0)
      pcall(conn.close, conn)
      self.socket=nil
      return startApp("OK: Timeout on waiting for provision service response")
    end
  end
-- end
