esrf

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

#%TITLE% OPIOM.MAC
#
#%NAME%
#  OPIOM.MAC - Macros for operating and testing OPIOM units
#
#
#%CATEGORY% Generic I/O, Isg
#
#%OVERVIEW%
#
#  An interactive macro %B%opiom%B% can be used for device configuration and
#  monitoring.
#  %BR%
#  More than one OPIOM module can be operated through this macro set.
#
#%EXAMPLE%
#  %DL%
#  %DT%opiomsetup op1 2 address=O1
#  %DD%Configures a OPIOM unit connected to the serial line #2 with address
#      O1 and assigns the name \"op1\" to it .
#  %DT%opiomsetup ldet2 id33/serial/0 address=2
#  %DD%Configures a OPIOM unit connected in the second position of a daisychain
#      accesed by the ESRF device id33/serial/0
#      and assigns the name \"ldet2\" to it .
#  %DT%opiom
#  %DD%Starts the interactive test program with the default module.
#  %XDL%
#
#%DEPENDENCIES%
#  These macros make use of the following macro sets:
#  %UL%
#  %LI%stlist.mac
#  %LI%isgdevice.mac
#  %LI%isg.mac
#  %XUL%

#%SETUP%
# A %B%opiomsetup%B% macro must be included in the setup file for every OPIOM
# module configured. Each module is identified by its name that must be a unique
# isgdevice identifier.
#%END%

#$Log: opiom.mac,v $
#Revision 1.6  2009/01/16 10:34:52  guilloud
#improve error message if opiomsetup error
#
#Revision 1.5  2008/08/12 15:19:20  rey
#documentation changes.
#
#Revision 1.4  2004/03/29 16:35:15  fajardo
#Revision log added
#

jtdo("isgdevice.mac")
jtdo("isg.mac")

#%UU% <opiom_name> <serline> [<parameter>=<value> ...]
#%MDESC%
#  Configures an opiom module connected to <serline> with the name <opiom_name>.
#  The following optional parameters can be also set.
#  %UL%
#  %LI%Valid parameters:%DL%
#    %DT%address=<addr>
#    %DD%This parameter allows to address a particular unit when the serial
#        line is shared by several isgdevices in dasychain.
#        If <addr> is a non-numerical value, it is treated as the isgdevice
#        address set by the ADDR command and stored internally in the unit.
#        On the other hand if <addr> is a numerical value it indicates the
#        relative position of the module in the serial line chain starting
#        from 0.
#        If this parameter is not specified, %B%spec%B% looks for the
#        first module in the chain.
#    %XDL%
#  %XUL%
def opiomsetup '{
    local retval

    if ($# == 0 || (retval = _opiomsetup("$*"))) {
        if (SETUP) {
            print "/-------- OPIOM ERROR ---------------\\"
            print "|  Error in line: $0 $*   "
            print "\\------------------------------------/"
        }
        if (retval < 0) {
            print "Usage:  $0 serial_line [parameter=value ...]"
            if (yesno("\nDisplay online help", 0)) eval("help local opiom")
        }
    }
}'


def _opiomsetup(args) '{
   global OPIOM[]
   global OPIOM_AUX[]

   local i nparam auxlist0[] auxlist1[] larr
   local serlin isgdev isgname

   nparam = split(args, auxlist0)
   for (i = 0; i < nparam; i++) {
      if (split(auxlist0[i], larr, "=") > 1){
         delete auxlist0[i]
         auxlist1[larr[0]] = larr[1]
      } else if (i > 1) {
         delete auxlist0[i]
         auxlist1[larr[0]] = "yes"
      }
   }
   if (!((0 in auxlist0) && (1 in auxlist0))) {
      printf("Bad parameters\n")
      return(-1)
   }
   isgname = auxlist0[0]
   serlin = auxlist0[1]

   if ("address" in auxlist1){
      if (auxlist1["address"] + 0 == auxlist1["address"])
         isgdev = isgdevice_add(isgname, serlin , 0, auxlist1["address"])
      else
         isgdev = isgdevice_add(isgname, serlin , 1, auxlist1["address"])
      delete auxlist1["address"]
   } else
      isgdev = isgdevice_add(isgname, serlin , 3, "OPIOM")

   if (isgdev <= 0 || isgdevice_check(isgname, 3, "OPIOM") == 0) {
      printf("No OPIOM device found at : %s\n", serlin)
      return(1)
   }

   if (OPIOM_AUX["setup_n"] != SETUP_N) {
      list_init OPIOM
      OPIOM_AUX["setup_n"] = SETUP_N
   }

   if (list_add(OPIOM, isgname) <= 0) {
      printf("Invalid OPIOM name: %s\n", isgname)
      return(-1)
   }

   OPIOM[isgname]["setup"] = "opiomsetup " args

   setup_tail("opiom", isgname)

   i = ""
   for (i in auxlist1) {
      print "Invalid parameter: " i "=" auxlist1[i]
   }
   if (i != "")
      return(-1)
   else
      return(0)
}'

def opiomunsetup '{
   local isgname

   isgname = "$1"
   cdef("", "", isgname, "delete")
   isgdevice_remove(isgname)

   list_remove(OPIOM, isgname)
   if (list_n(OPIOM) <= 0)
      unglobal OPIOM OPIOM_AUX
}'

def opiom_setdefault(isgname) '{
   if (OPIOM[0] <= 0) {
      print "No OPIOM devices configured. Use first \`opiomsetup\'."
      return(0)
   }
   if (isgname != "") {
      OPIOM_AUX["default"] = isgname
      if (!list_check(OPIOM, isgname)) {
         print "\`" isgname "\' is not a valid OPIOM unit."
      }
   }
   if (!list_check(OPIOM, OPIOM_AUX["default"])) {
      OPIOM_AUX["default"] = OPIOM[1]
      print "Setting \`" OPIOM_AUX["default"] "\' as default OPIOM unit."
   }
   return(1)
}'

#%UU% [<device_name>]
#%MDESC%
#  Macro that runs the interactive loop. %B%opiom%B% refresh certain
#  information on the screen and at the same time accepts commands
#  from the standard input.
#  %BR%
#
def opiom '{
   local isgname options

   isgname = $#? "$1": ""
   if (!$# || list_check(OPIOM, isgname) > 0){
      if (opiom_setdefault(isgname)) {
         isgname = OPIOM_AUX["default"]
         OPIOM[isgname]["prompt"] = "(" OPIOM_AUX["default"] ")"
      }
   } else if ((serdev = isgdevice_add("OPIOM", "$1", 3, "OPIOM")) > 0) {
      isgname = "OPIOM"
      OPIOM[isgname]["prompt"] = ""
   } else {
      print "No OPIOM unit found."
      isgname = ""
   }
   if (!isgname) {
      print "Usage: $0 opiom_name"
      print "  or   $0 serial_line"
      if (yesno("\nDisplay online help", 0))
         eval("help local opiom")
   } else {
      rdef isg_prompt  "opiom_prompt"
      rdef isg_update  "opiom_update"
      rdef isg_show    "opiom_show_comm"
      rdef isg_process "opiom_process_comm"

      isg_main(isgname, options, 0, OPIOM[isgname]["update"])
   }
}'


def opiom_update '{
   #update_flag = opiom_getstate(isgname)
}'

def opiom_getstate(isgname) '{
   local state refstat

   if ((state = isgdevice_comm(isgname, "?MODE")) == ISGDEV_ERR)
      state = "???"

   if (state != OPIOM[isgname]["state"]) {
      OPIOM[isgname]["state"] = state
      return(1)
   } else
      return(0)
}'


#%IU%
#%MDESC%
#  Displays the prompt on the screen. If the "update" flag is set also
#  displays the board status.
#
def opiom_prompt '
   printf("OPIOM%s", OPIOM[isgname]["prompt"])
'

def opiom_show_comm '
   isg_show_comm(".p, .program",  "Program mode")
   isg_show_comm(".e, .exec",     "Execute command")
   isg_show_comm(".c, .config",   "Display spec setup")
'

#%IU%
#%MDESC%
#
def opiom_process_comm '
   if (comm[0] == ".program" || comm[0] == ".p") {
      local aux

      opiom_upload_program(isgname)
      return(1)

   } else if (comm[0] == ".exec" || comm[0] == ".e") {
      line = substr(line, length(comm[0]) + 1)
      isg___command(isgname, line)
      return(1)

   } else if (comm[0] == ".config" || comm[0] == ".c") {
      local aux

      print
      printf("\tSerial line: %s\n", ISGDEV_CONF[isgname]["serlin"])
      printf("\tPosition   : %d\n", ISGDEV_CONF[isgname]["pos"])
      print
      printf("\tSetup line: %s\n", OPIOM[isgname]["setup"])
      return(1)
   }
'


def opiom_getopmoffsets(opmarray, roffsets)'{
   local i offset

   #read the file offsets like python struct.unpack
   roffsets["header"] = opiom_calcoffset(opmarray, 0)
   roffsets["src"] = opiom_calcoffset(opmarray, 1)
   roffsets["src_cc"] = opiom_calcoffset(opmarray, 2)
   roffsets["src_c"] = opiom_calcoffset(opmarray, 3)
   roffsets["jed"] = opiom_calcoffset(opmarray, 4)
}'

def opiom_calcoffset(data, i) '{
   local offset
   local OFF_BYTES HDR_CHARS

   OFF_BYTES = 2  #Offset bytes
   HDR_CHARS = 3  #Previous file chars(1byte)

   offset = data[(i * OFF_BYTES) + HDR_CHARS]
   offset |= data[(i * OFF_BYTES) + HDR_CHARS + 1] << 8

   return offset
}'

def opiom_opm_header(path, file, opminfo) '{
   local line i

   filepath = path file
   if (getline(filepath, "open") < 0) {
      return(-1)
   }

   for (i = 0; i < 25; i++) {
      local _line

      _line = getline(filepath)
      if (index(_line, "#user#")) {
         line = _line
         break
      }
   }
   getline(filepath, "close")

   if (!line)
      return(-1)

   opminfo["user"]     = opiom_opm_hextract(line, "#user#")
   opminfo["beamline"] = opiom_opm_hextract(line, "#beamline#")
   opminfo["project"]  = opiom_opm_hextract(line, "#project#")
   opminfo["comment"]  = opiom_opm_hextract(line, "#comment#")
   opminfo["pldid"]    = opiom_opm_hextract(line, "#pldid#")
   opminfo["date"]     = opiom_opm_hextract(line, "#date#")
   opminfo["time"]     = opiom_opm_hextract(line, "#time#")

   return(0)
}'

def opiom_opm_hextract(line, field) '{
   local beg len

   beg = index(line, field)
   if (!beg)
      return("-")

   beg += length(field)
   len = index(substr(line, beg), field) - 1
   return(substr(line, beg, len))
}'

def opiom_list_files(path, pldid) '{

   local aux filelist[] opminfo[] file selected

   uxcom = "cd " path "; ls *.opm"
   unix(uxcom, aux)
   n = split(aux, filelist, "\n")
   filelist[n++] = "default"

   print "File                                Date        User             Project"
   print "----------------------------------  ----------  ---------------  ---------------"
   selected = 0
   for (i = 0; i < n; i++) {
      local epoch

      if ((file = filelist[i]) == "")
         continue
      opminfo["pldid"] = 0
      opminfo["date"] = "--/--/----"
      opminfo["user"] = "-"
      opminfo["project"] = "???"

      if (file == "default") {
         opminfo["pldid"] = 0x0000FF
         opminfo["project"] = "<default>"

      } else
         opiom_opm_header(path, file, opminfo)

      if (pldid == opminfo["pldid"])
         tty_cntl("so")
      printf("%-35s %-10s  %-16s %s\n", file, \
              opminfo["date"], opminfo["user"], opminfo["project"])
      tty_cntl("se")
      if (opminfo["pldid"] > epoch) {
         epoch = opminfo["pldid"]
         selected = i
      }
   }
   return(filelist[selected])
}'

def opiom_upload_program(opiom_name, file) '{
   local opminfo[] path filepath
   local opmsize srcsz binsz
   local roffsets[]

   if (whatis("BLISSADM") & 0x04000000) {
      path = BLISSADM "/local/isg/opiom/"
   } else {
      path = SPECD "/../local/isg/opiom/"
   }
   if (!file) {
      file = opiom_list_files(path, isgdevice_comm(opiom_name, "?PLDID"))
      file = getval("\nFile to load", file)
      if (!file || index(file, "*"))
         return(0)
      if (file == "default") {
         if (yesno("\nProgram the PLD with the default user code", 0)) {
            print
            opiom_cpld_prog(opiom_name,0,0)
         }
         return
      }
      if (!index(file, "."))
         file = file ".opm"
   }
   if (opiom_opm_header(path, file, opminfo) < 0) {
      print "Problem reading file: " file
      return(-1)
   }
   filepath = path file
   opmsize = file_info(filepath,"size")

   local ubyte array opmfile[opmsize]

   fmt_read(filepath,"raw",opmfile)

   opiom_getopmoffsets(opmfile, roffsets)

   print
   print "============================================="
   print  "File    : " file
   print  "Date    : " opminfo["date"], "["opminfo["time"]"]"
   print  "User    : " opminfo["user"]
   print  "Beamline: " opminfo["beamline"]
   print  "Project : " opminfo["project"]
   print  "Comment : " opminfo["comment"]
   printf("PLD id  : %08X\n", opminfo["pldid"])
   print "============================================="


   if (yesno("\nDisplay PLD user code", 0)) {
      local i

      print "\nBegin ::::::::::::::::::::::::::: Verilog User code\n\n"
      for(i = roffsets["src"]; i < roffsets["src_cc"]; i++)
         printf("%c",opmfile[i])
      print
      print "\nEnd ::::::::::::::::::::::::::::: Verilog User code\n\n"
   }

   if (yesno(sprintf("\nLoad program (%s) into the device", file), 0)) {
      #Send the program command

      # module size testing(if) "?SRCSZ"
      if ((srcsz = isgdevice_comm(opiom_name, "?SRCSZ")) == ISGDEV_ERR) {
         print "Cannot talk to \'" opiom_name "\'"
         return(-1)
      }
      sscanf(srcsz, "%d", srcsz)

      if ((roffsets["src_c"] - roffsets["src_cc"]) < srcsz) {
         SRCST = roffsets["src_cc"]
         srcsz = roffsets["src_c"] - roffsets["src_cc"]
      } else {
         SRCST = roffsets["src_c"]
         srcsz = roffsets["jed"] - roffsets["src_c"]
      }
      binsz = opmsize - roffsets["jed"]

      local ubyte array sendarray[srcsz + binsz]

      # locate into sendarray the compressed fonts
      # with or without comments

      sendarray[0:srcsz-1] = opmfile[SRCST:SRCST+srcsz-1]

      # locate into sendarray the entire binary JEDEC compressed file

      sendarray[srcsz:] = opmfile[roffsets["jed"]:]

      #instruction for starting download
      opiom_cpld_prog(opiom_name, sendarray, binsz, srcsz, 256, \
                                  opminfo["pldid"], opminfo["project"])

      return(1)
   } else
      return(0)
}'

def opiom_cpld_prog(name, dat, binsz, srcsz, fsize, pldid, pldname) '{
   local tsize page csz frame_n answer retry
   local pstat
   local answer pstat newpstat progress

   answer = isgdevice_comm_ack(name, "MODE program")
   if (answer != "OK"){
      print "ERROR!"
      return(-1)
   }

   if (binsz == 0) {
      answer = isgdevice_comm_ack(name, sprintf("PROG DEFAULT", \
                            binsz, srcsz, fsize, pldid, pldname))
      if (answer != "OK"){
         print "ERROR!"
         return(-1)
      }

   } else {
      answer = isgdevice_comm_ack(name, sprintf("PROG %d %d %d %d \"%s\"", \
                            binsz, srcsz, fsize, pldid, pldname))
      if (answer != "OK"){
         print "ERROR!"
         return(-1)
      }
      tsize = binsz + srcsz

      print
      for (csz = 0; csz < tsize; csz += fsize) {
         page = tsize - csz
         if (page > fsize)
            page = fsize

         frame_n = csz / fsize

         comm = sprintf("#*FRM %d", frame_n)
         for (retry = 0 ; retry < 3; retry++) {
            printf("\r - LOAD %d%% ", 100 * csz / tsize)
            answer = isgdevice_bincomm(name, comm, dat[csz:], page)
            if (answer > 0)
               break

            printf("\n   ERROR. Retrying frame %d\n", frame_n)
         }
         if (answer <= 0) {
            print "   Aborting  PLD programming."
            return(-1)
         }
      }
      while (isgdevice_comm(name, "?PSTAT") == pstat)
         ;
      printf ("\r - LOAD (100%)\n")
      pstat = ""
   }

   while (1) {

      answer = isgdevice_comm(name, "?PSTAT")
      if (sscanf (answer, "%s %d", newpstat, progress) < 2) {
         break;
      }

      if (newpstat != pstat) {
         if (pstat != "")
            printf ("\r - %s (100%)\n", pstat)
         pstat = newpstat
      }
      printf ("\r - %s ", answer)
      sleep(.1)
   }
   if (newpstat == "DONE") {
      printf ("\r - %s (100%)\n", pstat)
      print "\nPLD succesfully programmed"
      return(0)
   } else {
      printf("\nError programming PLD (%s)\n", isgdevice_comm(name, "?PERR"))
      return(-1)
   }

}'

def opiom_bin_tpg(opiom_name, tpgtab, nlines) '{
   local comm answer tsize dsize

   max_time = array_op("max", tpgtab[][1])
   if (max_time < 0x100) {
      tsize = "BT"
      dsize = 2
   } else if (max_time < 0x10000) {
      tsize = "WT"
      dsize = 3
   } else {
      tsize = "LT"
      dsize = 5
   }

   ubyte array alldata[nlines * dsize]

   for (i = idx = 0; i < nlines; i++, idx += dsize) {
      alldata[idx] = tpgtab[i][0];
      tpg_time = tpgtab[i][1]
      if (dsize == 2)
         alldata[idx + 1] = tpg_time
      else if (dsize == 3) {
         alldata[idx + 1] = tpg_time >> 8
         alldata[idx + 2] = tpg_time
      } else {
         alldata[idx + 1] = tpg_time >> 24
         alldata[idx + 2] = tpg_time >> 16
         alldata[idx + 3] = tpg_time >>  8
         alldata[idx + 4] = tpg_time
      }
   }

   comm = sprintf("#*TPG ADD 0x%x %s", nlines, tsize)
   answer = isgdevice_bincomm(opiom_name, comm, alldata, dsize * nlines)
   return
}'

#%MACROS%

#%AUTHOR% P.Fajardo, (Original 04/02).
#  $Revision: 1.6 $ / $Date: 2009/01/16 10:34:52 $
#%TOC%