esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% WAGO.MAC
#%NAME%
#  Macro functions to access WAGO I/O modules.
#
#%DESCRIPTION%
#  This macro set implements communication with modules of the 
#  WAGO-I/O-SYSTEM 750 through field bus couplers for MODBUS over serial 
#  lines or MODBUS/TCP over Ethernet TCP/IP.%BR%
#
#%EXAMPLE%
#
#  %B%wagosetup%B% %BR%
#  %B%print wago_read("temp", 2, "IW")%B% %BR%
#  This prints the value of the 3rd input register associated to the function
#  name "temp".%BR%
#  %B%wago_write("myout", 0, 1, "OB")%B% %BR%
#  This macro sets the first output bit of "myout" to 1.%BR%
#

#%UU% 
#%MDESC%
#  .%BR%
#
def wagosetup '_wagosetup(0)'

#%UU% 
#%MDESC%
#  .%BR%
#
def wagoshow '_wagosetup(1)'

#%IU% 
#%MDESC%
#  .%BR%
#
def _wagosetup(show) '{
   global WAGO[]
   global WAGOCONFIG[]
   global WAGOFUNCT[]
   global WAGO_ERR
   global MODB_ERR
   local configf setupf editor 

   if (whatis("BLISSADM") & 0x04000000) {
      configf = BLISSADM "/spec/macros/wago.config"
      setupf  = BLISSADM "/local/spec/userconf/" SPECBL "config.wago"
   } else {
      configf = SPECD "/../jmacros/wago.config"
      setupf  = sprintf("%s/../local/userconf/%sconfig.wago", SPECD, SPECBL)
   }

   if (!SETUP && !show) {
      if (SEDITOR == "") {
         print "Cannot open file editor. No editor configured"
      } else {
         if (GUI_RUN)
            editor = sprintf("xterm -tn vt100 -e %s", SEDITOR)
         else
            editor = SEDITOR
         unix(sprintf("%s %s", editor, setupf))
      }
   }
   if (wago__conf(configf) > 0) {
      wago__nodes(setupf, show)
   }
   setup_tail("wago")
}'

#%IU%
#%MDESC%
#  .%BR%
#
def wagounsetup '{
   unglobal WAGO
   unglobal WAGOCONFIG
   unglobal WAGOFUNCT
   unglobal WAGO_ERR
}'

#%IU% (<config_file>])
#%MDESC%
#  .%BR%
#
def wago__conf(cfile) '{
   local line
   local ref ib ob iw ow desc

   if (!file_info(cfile)) {
      print " WAGO: Can not access configuration file ", cfile
      return (-1)
   }
   if (SETUP && WAGO["conftime"] == file_info(cfile, "mtime")) {
      return(WAGO["nconf"])
   }

   getline(cfile, "close")
   if (getline(cfile, "open") == -1) {
      print " WAGO: Can not open configuration file ", cfile
      return(-1)
   }
   
   for (line in WAGOCONFIG) delete WAGOCONFIG[line]
   WAGO["nconf"] = 0

   printf("Reading file \"%s\"\n", cfile)

   while((line = getline(cfile)) != -1) {
      c = substr(line, 1, 1)
      if (asc(c) < 32 || c == "#")
         continue

      if (sscanf(line, " %[^,], %g, %g, %g, %g, %[^\n\r]", \
                          ref,  ib, ob, iw, ow, desc) != 6) {
         printf("  Bad line in \"%s\": %s\n", cfile, line)
         continue
      }
      WAGOCONFIG[ref] = WAGO["nconf"]++
      WAGOCONFIG[ref]["ib"] = ib
      WAGOCONFIG[ref]["ob"] = ob
      WAGOCONFIG[ref]["iw"] = iw
      WAGOCONFIG[ref]["ow"] = ow
      WAGOCONFIG[ref]["desc"] = desc
   }
   WAGO["conftime"] = file_info(cfile, "mtime")
   getline(cfile, "close")
   return(WAGO["nconf"])
}'

#%IU% (<setup_file>])
#%MDESC%
#  .%BR%
#
def wago__nodes(nfile, show) '{
   local line node nodename
   local type device addr nmod
   local nametable[]
   short array modtable[64][4]

   if (!file_info(nfile, "-r")) {
      print " WAGO: Can not access setup file ", nfile
      return (-1)
   }

   getline(nfile, "close")
   for (line in WAGOFUNCT) delete WAGOFUNCT[line]

   printf("Reading file \"%s\"\n", nfile)

   WAGO["nfunc"] = 0
   node = 0
   while ((line = getline(nfile)) != -1) {
      c = substr(line, 1, 1)
      if (asc(c) < 32 || c == "#")
         continue

      if (!node) {
         addr = -1
         device = other = ""
         if (sscanf(line, " node %s %s %d %s %s", \
                          type, nodename, addr, device, other) >= 2 && \
           (type == "tcp" || (type == "serial" && addr >= 0 && device != ""))) {
            if (type == "tcp") {
               device = nodename
               if (addr < 0) addr = 0xFF
            }
            if (show) {
               printf("\nI/O station: %s ", nodename)
               if (type == "tcp")
                  printf("(tcp)\n")
               else
                  printf("(%s ## %s)\n", device, addr)
            }
         } else {
            printf("  Bad line in \"%s\": %s\n", nfile, line)
            return(-1)
         }
         node = 1
         nmod = 0

      } else {
         name = ""
         sscanf(line, " %s %s", ref, name)
         if (ref == "node") {
            printf("  Bad line in \"%s\": %s\n", nfile, line)
            print "  Node terminator is probably missing."
            return(-1)
         }
         if (!(ref in WAGOCONFIG)) {
            printf("  WAGO reference `%s\' not known.\n", ref)
            return(-1)
         } else if (show) {
            printf("  %2d - %s - %s\n", nmod, ref, WAGOCONFIG[ref]["desc"])
         }
         nametable[nmod] = name
         modtable[nmod][0] = WAGOCONFIG[ref]["ib"]
         modtable[nmod][1] = WAGOCONFIG[ref]["ob"]
         modtable[nmod][2] = WAGOCONFIG[ref]["iw"]
         modtable[nmod][3] = WAGOCONFIG[ref]["ow"]
         if (modtable[nmod][0] == -1) {
            wago__addnode(nodename, device, addr, nametable, modtable, nmod)
            node = 0
         } else if(array_op("sum", modtable[nmod]) > 0) {
            nmod++
         } 
      }
   }
   if (node) {
      print "  Node terminator is probably missing."
      return(-1)
   }
   getline(nfile, "close")
}'

#%IU% (<name>, <device>, <addr>, <nametab>, <dtable>, <nmod>)
#%MDESC%
#  .%BR%
#
def wago__addnode(nodename, device, addr, nametab, table, n) '{
   short array bas[4] len[4] oth[4]
   local modbnode idx hostn

   if ((idx = index(device, ":")) != 0){
      unix("hostname", hostn="")
      sscanf(hostn, "%s", hostn)
      if (substr(device, 1, idx - 1) != hostn) {
         if (!SETUP)
            printf("  Not the right host for node %s (%s).\n", nodename, device)
         return
      }
      device = substr(device, idx + 1)
   }
   if (substr(device, 1, 5) == "/dev/") {
# Check for device
      if (1 && !SETUP) {
         printf("  Device %s (node %s) not configured as serial interface.\n",\
                     device, nodename)
         return
      }
      device = 99
   }
   MODB_ERR = -1
   modbnode = modb_addnode(device, addr, nodename)
   if (MODB_ERR == 1001) {
      printf("  Interface error (%s) with node \'%s\'\n", device, nodename)
      return
   } else if (MODB_ERR == 1002) {
      printf("  Bad address (%d) for node \'%s\'\n", addr, nodename)
      return
   } else if (MODB_ERR) {
      printf("  Node \'%s\' does not respond (%s, %d)\n", nodename, device, addr)
      return
   } else {
# Add i/o bits/words and check with real device before
      len[0] = array_op("sum", table[][0]) 
      len[1] = array_op("sum", table[][1]) 
      len[2] = array_op("sum", table[][2]) 
      len[3] = array_op("sum", table[][3])
#p len
#      modb_read_multregs(modbnode, 0x1022, 4, oth)
#p oth
#      if (array_op("sum", oth != len) != 0) {
#         printf("  Node \'%s\' does not match settings.\n", nodename)
#         return
#      } 
   }

   funct = 0
   bas = 0
   for (i = 0; i < n; i++) {
      name = nametab[i]
      if (name == "") {
         bas += table[i]
         continue
      }
      
      if (name in WAGOFUNCT) {
         printf("  Invalid function name %s in node %s\n", name, nodename)
         bas += table[i]
         continue
      }
      len = table[i]
      oth = 0
      for (j = i + 1; j < n; j++) {
         if (name == nametab[j]) {
            nametab[j] = ""
            len += table[j]
            if (array_op("sum", len * oth) > 0) {
               print "  Non consecutive modules/addresses for function", name
               return(-1)
            }
         } else {
            oth += table[j]
         }
      }
      WAGOFUNCT[name] = WAGO["nfunc"]++
      WAGOFUNCT[name]["node"] = modbnode
      WAGOFUNCT[name]["b_IB"] = bas[0]
      WAGOFUNCT[name]["b_OB"] = bas[1]
      WAGOFUNCT[name]["b_IW"] = bas[2]
      WAGOFUNCT[name]["b_OW"] = bas[3]
      WAGOFUNCT[name]["n_IB"] = len[0]
      WAGOFUNCT[name]["n_OB"] = len[1]
      WAGOFUNCT[name]["n_IW"] = len[2]
      WAGOFUNCT[name]["n_OW"] = len[3]

      funct++
      bas += table[i]
   }
   return(funct)
}'


#%IU% (<modname>, <addr>, <dtype>, <nval>)
#%MDESC%
#  .%BR%
#
def wago__check(name, addr, dtype, nval) '{
   local base len

   if (!(name in WAGOFUNCT)) {
      if (WAGO_ERR != -1)
         printf("Not a valid wago name: %s\n", name)
      return(-1)
   }
   base = WAGOFUNCT[name]["b_" dtype]
   len  = WAGOFUNCT[name]["n_" dtype]
   if (addr < 0 || (addr + nval) > len) {
      if (WAGO_ERR != -1) {
         printf("Not valid \'%s\' address range (%d-%d) for wago name: %s\n", \
                        dtype, addr, addr + nval - 1, name)
      }
      WAGO_ERR = 101
      return(-1)
   }
   WAGO["currnode"] = WAGOFUNCT[name]["node"]
   WAGO["curraddr"] = base + addr
   WAGO_ERR = 0
   return(0)
}'

#%UU% (<fname>, <faddr> [, <dtype>])
#%MDESC%
#  .%BR%
#
def wago_read(name, addr, dtype) '{
   local data[]

   if (whatis("dtype") & 0x08000000)
      dtype = "IW"

   if (wago_mread(name, addr, 1, data, dtype) > 0)
      return(data[0])
   else
      return(-1)
}'

#%UU% (<fname>, <faddr>, <nval>, <data> [, <dtype>])
#%MDESC%
#  .%BR%
#
def wago_mread(name, addr, nval, data, dtype) '{
   local node eaddr

   if (whatis("dtype") & 0x08000000)
      dtype = "IW"

   if (wago__check(name, addr, dtype, nval) < 0)
      return(-1)

   node = WAGO["currnode"]
   eaddr = WAGO["curraddr"]

   if (dtype == "IW") {
      return(modb_read_inpregs(node, eaddr, nval, data))
   } else if (dtype == "OW") {
      eaddr += 0x0200
      return(modb_read_inpregs(node, eaddr, nval, data))
   } else if (dtype == "IB") {
      return(modb_read_coils(node, eaddr, nval, data))
   } else if (dtype == "OB") {
      eaddr += 0x0200
      return(modb_read_coils(node, eaddr, nval, data))
   } else
      return(-1)
}'

#%UU% (<fname>, <faddr>, <value> [, <dtype>])
#%MDESC%
#  .%BR%
#
def wago_write(name, addr, value, dtype) '{
   local node eaddr

   if (whatis("dtype") & 0x08000000)
      dtype = "OW"

   if (wago__check(name, addr, dtype, 1) < 0)
      return(-1)

   node = WAGO["currnode"]
   eaddr = WAGO["curraddr"]

   if (dtype == "OW") {
      return(modb_write_reg(node, eaddr, value))
   } else if (dtype == "OB") {
      return(modb_write_coil(node, eaddr, value))
   } else {
      if (WAGO_ERR != -1) {
         printf("Not output wago data type: %s\n", dtype)
      }
      WAGO_ERR = 110
      return(-1)
   }
}'

#%UU% (<fname>, <faddr>, <nval>, <data> [, <dtype>])
#%MDESC%
#  .%BR%
#
def wago_mwrite(name, addr, nval, data, dtype) '{
   local node eaddr

   if (whatis("dtype") & 0x08000000)
      dtype = "OW"

   if (wago__check(name, addr, dtype, nval) < 0)
      return(-1)

   node = WAGO["currnode"]
   eaddr = WAGO["curraddr"]

   if (dtype == "OW") {
      return(modb_write_regs(node, eaddr, nval, data))
   } else if (dtype == "OB") {
      return(modb_force_coils(node, eaddr, nval, data))
   } else {
      if (WAGO_ERR != -1) {
         printf("Not output wago data type: %s", dtype)
      }
      WAGO_ERR = 110
      return(-1)
   }
}'


def multim_init_wago '
   global WAGO_MULTIM[]

   if (whatis("WAGOFUNCT") == 0) {
      printf("wagosetup must be run before multimsetup type=wago\n")
      return 1
   }

   if ("group" in MULTIM[cntr]) {
      local group channel
      
      group = MULTIM[cntr]["group"]
      if ("channel" in MULTIM[cntr])
         channel = MULTIM[cntr]["channel"]
      else {
         channel = counter_par(cntr, "channel")
         MULTIM[cntr]["channel"] = channel
      }

      if (channel < 0) {
         printf("Invalid WAGO channel %d in counter %s\n", channel, \
                cnt_mne(cntr))
         return 1
      }
      else if (channel >= WAGOFUNCT[group]["n_IW"]) {
         local msg
         msg = "WAGO Channel %d greater than nr. of configured channels " \
               "in group \"%s\" (=%d)\n"
         printf(msg, channel, group, WAGOFUNCT[group]["n_IW"])
         return 1
      }

#      if (!("offset" in MULTIM[cntr]))
#         MULTIM[cntr]["offset"] = 0
#      else
#         MULTIM[cntr]["offset"] /= MULTIM[cntr]["scale"]
   }
   else {
      printf("No \"group\" parameter in multimsetup for WAGO counter %s\n", \
             cnt_mne(cntr))
      return 1 
   }

'


#def multim_read_wago '
#
#   if ("group" in MULTIM[cntr]) {
#      local group channel
#      group = MULTIM[cntr]["group"]
#      if (WAGO_MULTIM[group]["t0"] != MULTIM["t0"]) {
#         wago_multim_read_all(group)
#         WAGO_MULTIM[group]["t0"] = MULTIM["t0"]
#      }   
#
#      channel = MULTIM[cntr]["channel"]
#      if (WAGO_MULTIM[group]["nrchan"] > channel) {
#         value = WAGO_MULTIM[group][channel] + MULTIM[cntr]["offset"]
#         ok = 1
#      }
#   }
#'

def multim_read_wago '

   if ("group" in MULTIM[cntr]) {
      local group channel
      group = MULTIM[cntr]["group"]
      if (MULTIM["loop_n"] > WAGO_MULTIM[group]["last_n"]) {
         wago_multim_read_all(group)
         WAGO_MULTIM[group]["last_n"] = MULTIM["loop_n"]
      }

      channel = MULTIM[cntr]["channel"]
      if (WAGO_MULTIM[group]["nrchan"] > channel) {
         value = WAGO_MULTIM[group][channel] + MULTIM[cntr]["offset"]
         ok = 1
      }
   }
'


def wago_multim_read_all(group) '{
   local nrchan indx

   nrchan = WAGOFUNCT[group]["n_IW"]

   local short array arr[nrchan]

   nrchan = wago_mread(group, 0, nrchan, arr)
   WAGO_MULTIM[group]["nrchan"] = nrchan

   for (indx = 0; indx < nrchan; indx++)
      WAGO_MULTIM[group][indx] = arr[indx]
}'

#%MACROS%
#%DEPENDENCIES%
#  This macro set needs modbus.mac to access MODBUS devices.
#
#%INTERNALS%
#  ???.
#
#%AUTHOR% P. Fajardo, (Original 5/01).
#  $Revision: 1.1 $ / $Date: 2003/03/31 11:17:54 $
#%TOC%