Best Python code snippet using avocado_python
wrapper.py
Source:wrapper.py  
1"""This script helps you wrap a Fortran subroutine so you2can call it from NCL."""3#4# This script asks you a bunch of questions about a Fortran routine5# that you want wrap and call from NCL. It then creates an interface6# C wrapper routine and a code snippet for registering the routine (this7# code snippet goes in "wrapper.c").8#9# There are some things that need to be added to this program:10# 11#  1. Recognition of work arrays12#  2. Ask if input arrays are not allowed to have missing values13#     (this is checked via "contains_missing").14#  3. Needs more testing with variables that don't have leftmost15#     dimensions.16#  4. More testing with scalars. I think there's something odd with these.17#  5. Better handling of array dimensions that are fixed. For example18#        for an array that is 2 x nx x ny, this program doesn't handle19#        the '2' part very well.20#21#22# Initialize some stuff.23#24args                = []25farg_names          = []26farg_cchar          = []27farg_types          = []28global_dsizes_names = []29global_var_names    = []30global_var_types    = []31global_calling_char = []32global_dsizes_names_accum = []33various_var_names   = []34various_var_types   = []35work_array_names    = []36work_array_types    = []37index_names         = []38debug               = True39have_leftmost       = False40ntypes = ['numeric','double','float','long','integer','string','logical']41ctypes = [   'void','double','float','long',   'int','string','logical']42reserved_names = ['i', 'ndims_leftmost', 'size_leftmost', 'size_output']43#44# Set up class that will hold information on NCL input arguments.45#46class Argument:47  def __init__(self,arg_num,name,itype,sets_otype,ndims,dsizes=None,48               min_ndims=0,dsizes_names=None,dsizes_names_str="",49               has_missing=False):50    self.arg_num    = arg_num       # Number of argument, -1 indicates51                                    # return value.52    self.name       = name53    self.ntype      = ntypes[itype]54    self.ctype      = ctypes[itype]55    self.sets_otype = sets_otype56    self.ndims      = ndims57    self.min_ndims  = min_ndims58    if ndims == 1 and dsizes[0] == 1:59      self.is_scalar = True60    else:61      self.is_scalar = False62#63# These are variable names that we use in the C code to hold64# number of dimensions, dimension sizes, types, missing values, and65# temporary names for various input arguments. Note that not all of66# these names will necessarily be used in the code. They are67# conditional on several factors, like whether the type is numeric,68# and whether the array has leftmost dimensions.69#70    self.ndims_name   = "ndims_" + name71    self.type_name    = "type_" + name72    self.dsizes_name  = "dsizes_" + name73    self.has_msg_name = "has_missing_" + name74    self.msg_name     = "missing_"     + name75    self.msg_dname    = "missing_dbl_" + name76    self.msg_fname    = "missing_flt_" + name77    self.tmp_name     = "tmp_" + name78    self.index_name   = "index_" + name79    if dsizes != None:80      self.dsizes      = dsizes81    if dsizes_names != None:82      self.dsizes_names     = dsizes_names83      self.dsizes_names_str = dsizes_names_str84    self.has_missing = has_missing85#86# Set up instructions on how to print an instance of this class.87#88  def __str__(self):89    if self.arg_num >= 0:90      str1 = "Name of argument " + str(self.arg_num) + " is '" +  \91              self.name + "'\n"92    else:93      str1 = "Name of return argument is '" + self.name + "'\n"94    str1 = str1 + "  NCL type is " + self.ntype + "\n"95    str1 = str1 + "    C type is " + self.ctype + "\n"96    if self.has_missing:97      str1 = str1 + "    This variable can contain a missing value.\n"98    if self.ndims > 0:99      if self.is_scalar:100        str1 = str1 + "  This variable is a scalar\n"101      else:102        str1 = str1 + "  Number of dimensions is " + str(self.ndims) + "\n"103        str1 = str1 + "  Name of variable that holds # of dimemsions is " + \104               self.ndims_name + "\n"105        str1 = str1 + "  Name of variable that holds dimemsion sizes is " + \106               self.dsizes_name + "\n"107        for i in range(self.ndims):108          if self.dsizes[i] > 1:109            str1 = str1 + "  Dimension # " + str(i) + " is length " +\110                          str(self.dsizes[i]) + "\n"111          else:112            str1 = str1 + "  Dimension # " + str(i) + " is variable\n"113    else:114      str1 = str1 + "  Number of dimensions is variable\n"115    if self.min_ndims > 0:116      str1 = str1 + "  Number of minimum dimensions is " + \117                    str(self.min_ndims) + "\n"118      for j in range(self.min_ndims):119        str1 = str1 + "  Dimension " + self.ndims_name + "-" + \120                      str(int(self.min_ndims-j)) + " is " + \121                      self.dsizes_names[j] + "\n"122    return str1123#124# Import some stuff.125#126import sys127from string import *128#129# Begin asking for input on function/procedure.130#131print "\nIn order to wrap your Fortran subroutine, I need"132print "to ask you a few questions.\n"133#134# Is this a function or procedure?135#136forp = raw_input("Is this going to be a function (f) or procedure (p)? [f] ")137if (lower(forp) == "p"):138  isfunc       = False139  wrapper_type = "procedure"140else:141  isfunc       = True142  wrapper_type = "function"143#144# Get Fortran, NCL, and wrapper names of function or procedure.145#146valid = False147while not valid:148  ncl_name = raw_input("\nEnter NCL/PyNGL name of your " + wrapper_type + ": ")149  if ncl_name == "":150    print "Invalid name for NCL/PyNGL function or procedure, reenter."151  else:152    valid = True153ncl_nameW = ncl_name + "_W"     # Name of wrapper.154valid = False155while not valid:156  fortran_name = raw_input("\nEnter Fortran name of your " + wrapper_type + \157                           ": ")158  if fortran_name == "":159    print "Invalid name for Fortran subroutine, reenter."160  else:161    valid = True162valid = False163while not valid:164  wrapper_name = raw_input("\nEnter name you want to give the wrapper C file (without the 'W.c') " +\165                           ": ")166  if wrapper_name == "":167    print "Invalid name for wrapper name, reenter."168  else:169    valid = True170fatal_str        = '    NhlPError(NhlFATAL,NhlEUNKNOWN,"' + ncl_name + ': '171warn_str         = '    NhlPError(NhlWARNING,NhlEUNKNOWN,"' + ncl_name + ': '172return_fatal_str = '    return(NhlFATAL);\n'173#174# How many input arguments are there?175#176valid = False177while not valid:178  rinput = raw_input('\nHow many input arguments will there be for ' + \179                     ncl_name + '? ')180  try:181    num_args = int(rinput)182    if num_args < 0:183      print "Invalid number of arguments: ",num_args184      print "Reenter."185    elif num_args == 0:186      print "This script is for routines that contain arguments. Reenter."187    else:188      valid = True189  except:190      print "Must enter an integer > 0, reenter."191print "\nI need to ask you some questions about each input argument."192#193# Loop across the number of input arguments and get information194# about each one.195#196num_input_has_missing = 0       # Counter for how many input197                                # variables can have missing values.198for i in range(num_args):199#200# Get name of argument.201#202  valid = False203  while not valid:204    name = raw_input("\nWhat is the name of argument # " + str(i) + "? ")205    if name == "":206      print "Invalid name, reenter."207    elif name in reserved_names or name in global_var_names:208      print "Name already in use, reenter."209    else:210      valid = True211#212# Get type of argument.213#214  print "What type is '" + name + "'? [0]"215  for j in range(len(ntypes)):216    print "   ",j,":",ntypes[j]217   218  valid = False219  while not valid:220    rinput = raw_input()221    if rinput == "":222      itype = 0223      valid = True224    else:225      try:226        itype = int(rinput)227        if (itype < 0) or (itype >= len(ntypes)):228          print "Invalid type, reenter."229        else:230          valid = True231      except:232        print "Invalid type, reenter."233#234# Store this variable and its type in a list of variables we are235# keeping track of.236#237  if itype == 0:238    global_var_names.append("tmp_" + name)239    global_var_types.append(ctypes.index('double'))240  else:241    global_var_names.append(name)242    global_var_types.append(itype)243  global_calling_char.append("")244#245# If this input argument is numeric, then ask if its type246# determines the output type of the return value.247#248  if isfunc and itype == 0:249    rinput = raw_input("Does the type of " + name + " determine the type of the output? (y/n) [n] ")250  if (lower(rinput) == "y"):251    sets_otype = True252  else:253    sets_otype = False254#255# Ask about a missing value.256#257  rinput = raw_input("Can " + name + " have a _FillValue attribute? (y/n) [n] ")258  if (lower(rinput) == "y"):259    has_missing = True260    num_input_has_missing += 1261    if itype == 0:262      global_var_names.append("missing_dbl_" + name + ".doubleval")263      global_var_names.append("missing_flt_" + name + ".floatval")264      global_var_types.append(ctypes.index('double'))265      global_var_types.append(ctypes.index('float'))266      global_calling_char.append("&")267      global_calling_char.append("&")268    else:269      global_var_names.append("missing_" + name + "." + ctypes[itype] + "val")270      global_var_types.append(itype)271      global_calling_char.append("&")272  else:273    has_missing = False274#275# Get dimension sizes.276#277  print "How many dimensions does '" + name + "' have?"278  valid = False279  while not valid:280    rinput = raw_input("Enter <return> for variable dimensions: [0] ")281    if rinput == "":282      ndims = 0283      valid = True284    else:285      try:286        ndims = int(rinput)287        if ndims >= 0:288          valid = True289        else:290          print "Invalid number of dimensions, reenter."291      except:292        print "Must enter an integer, reenter."293  dsizes       = None294  dsizes_names = None295  min_ndims    = 0296  dsizes_names_str = ""297  if ndims > 0:298#299# Our array is a fixed number of dimensions.300#301    print "Enter dimension size of each dimension"302    print "(Hit <return> for variable dimension size)"303    dsizes = []304    for j in range(ndims):305      valid = False306      while not valid:307        rinput = raw_input("Size for dimension # " + str(j) + \308                           " of argument '" + name + "': ")309        if rinput == "":310          valid = True311          dsizes.append(0)312        else:313          try:314            if int(rinput) >= 0:315              valid = True316              dsizes.append(int(rinput))317            else:318              print "Invalid size for dimension, reenter."319          except:320            print "Must enter an integer, reenter."321  else:322#323# Our array is a variable number of dimensions. That is, it has324# leftmost dimensions.325#326    have_leftmost = True327    index_names.append("index_" + name)328#329# Get the minimum dimension size required.330#331    valid = False332    while not valid:333      rinput = raw_input("How many dimensions does the Fortran routine expect for this variable? ")334      try:335        min_ndims = int(rinput)336        if min_ndims > 0:337          valid = True338        else:339          print "Invalid number of dimensions, reenter."340      except:341        print "Must enter an integer > 0."342#343# Get the names of each non-leftmost dimension size.344#345  if not (ndims == 1 and dsizes[0] == 1):346    dsizes_names     = []347    dsizes_names_str = ""348    print "What are the names of each of these dimensions?"      349    if global_dsizes_names != []:350      print "You can use these existing names if they apply: " + \351             str(global_dsizes_names)352    for j in range(max(ndims,min_ndims)):353      if ndims > 0:354        dsizes_names.append(raw_input("Name of dimension " + str(j) + " : "))355      else:356        dsizes_names.append(raw_input("Name of dimension ndims_" + name + \357                                    "-" + str(int(min_ndims-j)) + " : "))358      if not dsizes_names[j] in global_dsizes_names: 359        global_dsizes_names.append(dsizes_names[j])360      if not dsizes_names[j] in global_var_names: 361        global_var_names.append(dsizes_names[j])362        global_var_types.append(ctypes.index('int'))363        global_calling_char.append("&")364#365# Create string for variable that will hold the size of these dimensions366# (rightmost dimensions for variables that have leftmost dimensions).367#368# For example, if the dimensions are nx, ny, and nz, then369# a variable called "nxnynz" will be created that is equal to 370# nx * ny * nz. 371#372      dsizes_names_str = dsizes_names_str + dsizes_names[j]373    if not dsizes_names_str in global_dsizes_names: 374      global_dsizes_names.append(dsizes_names_str)375    if not dsizes_names_str in global_var_names: 376      global_var_names.append(dsizes_names_str)377      global_var_types.append(ctypes.index('int'))378      global_calling_char.append("&")379#380# With all this information, create an instance of the Argument class.381#382  args.append(Argument(i,name,itype,sets_otype,ndims,dsizes,min_ndims, \383                       dsizes_names,dsizes_names_str,has_missing))384#385# Get information on the return value, if a function.386#387if isfunc:388  valid = False389  while not valid:390    ret_name = raw_input("\nWhat is the name of the return value? ")391    if ret_name == "":392      print "Invalid name, reenter."393    elif ret_name in reserved_names or ret_name in global_var_names:394      print "Name already in use, reenter."395    else:396      valid = True397#398# Get type of argument.399#400  print "What type is '" + ret_name + "'? [0] "401  for j in range(len(ntypes)):402    print "   ",j,":",ntypes[j]403   404  valid = False405  while not valid:406    rinput = raw_input()407    if rinput == "":408      ret_itype = 0409      valid = True410    else:411      try:412        ret_itype = int(rinput)413        if (ret_itype < 0) or (ret_itype >= len(ntypes)):414          print "Invalid type, reenter."415        else:416          valid = True417      except:418        print "Must enter an integer, reenter."419  if ret_itype == 0:420    global_var_names.append("tmp_" + ret_name)421    global_var_types.append(ctypes.index('double'))422  else:423    global_var_names.append(ret_name)424    global_var_types.append(ret_itype)425  global_calling_char.append("")426#427# Ask about a return missing value.428#429  rinput = raw_input('Can ' + ret_name + ' contain missing values? (y/n) [n] ')430  if (lower(rinput) == "y"):431    ret_has_missing = True432  else:433    ret_has_missing = False434#435# Find out which (if any) input variable the return value is dependent on.436# Only do this if there's at least one input value that can contain a437# missing value.438#439  if ret_has_missing and (num_input_has_missing > 0):440    rinput = raw_input("Is the return missing value based on any input missing values? (y/n) [y] ")441    if (lower(rinput) == "n"):442      ret_msg_depend_input = False443    else:444      ret_msg_depend_input = True445    if ret_msg_depend_input:  446      print "Select the input variable whose missing value determines"447      print "the missing value for the return variable:"448  449      for j in range(len(args)):450        if(args[j].has_missing):451          print "   ",j,":",args[j].name452   453      valid = False454      while not valid:455        rinput = raw_input()456        try:457          ret_msg_depend_index = int(rinput)458          if (ret_msg_depend_index < 0) or \459             (ret_msg_depend_index >= len(args)):460            print "Invalid entry, reenter."461          else:462            valid = True463        except:464          print "Must enter an integer, reenter."465#466# Get dimension sizes.467#468  print "How many dimensions does " + ret_name + " have?"469  valid = False470  while not valid:471    rinput = raw_input("Hit <return> for variable dimensions: ")472    if rinput == "":473      ret_ndims = 0474      valid = True475    else:476      try:477        ret_ndims = int(rinput)478        if ret_ndims < 0:479          print "Invalid number of dimensions, reenter."480        else:481          valid = True482      except:483        print "Must enter an integer >= 0, reenter."484  ret_dsizes       = None485  ret_dsizes_names = None486  ret_min_ndims    = 0487  ret_dsizes_names_str = ""488  if ret_ndims > 0:489    print "Enter dimension size of each dimension"490    print "(Hit <return> for variable dimension size)"491    ret_dsizes = []492    for j in range(ret_ndims):493      valid = False494      while not valid:495        rinput = raw_input("Size for dimension # " + str(j) + " of return value: ")496        if rinput == "":497          ret_dsizes.append(0)498          valid = True499        else:   500          try:      501            if int(rinput) < 0:502              print "Invalid size for dimension, reenter."503            else:504              ret_dsizes.append(int(rinput))505              valid = True          506          except:507            print "Must enter an integer, reenter."508  else:509    have_leftmost = True510    index_names.append("index_" + ret_name)511#512# Get the minimum dimension size required.513#514    valid = False515    while not valid:516      rinput = raw_input("How many dimensions does the Fortran routine expect for the return value? ")517      try:518        ret_min_ndims = int(rinput)519        if ret_min_ndims <= 0:520          print "Invalid number of dimensions, reenter."521        else:522          valid = True523      except:524        print "Must enter an integer > 0, reenter."525#526# Get the names of each non-leftmost dimension size.527#528  if not (ret_ndims == 1 and ret_dsizes[0] == 1):529    ret_dsizes_names     = []530    ret_dsizes_names_str = ""531    print "What are the names of each of these dimensions?"      532    if global_dsizes_names != []:533      print "You can use these existing names if they apply: " + \534            str(global_dsizes_names)535    for j in range(max(ret_ndims,ret_min_ndims)):536      if ret_ndims > 0:537        ret_dsizes_names.append(raw_input("Name of dimension " + str(j) + \538                                          " : "))539      else:540        ret_dsizes_names.append(raw_input("Name of dimension ndims_" + \541                   ret_name + "-" + str(int(ret_min_ndims-j)) + " : "))542        if not ret_dsizes_names[j] in global_dsizes_names: 543          global_dsizes_names.append(ret_dsizes_names[j])544        if not ret_dsizes_names[j] in global_var_names: 545          global_var_names.append(ret_dsizes_names[j])546          global_var_types.append(ctypes.index('int'))547          global_calling_char.append("&")548#549# Create string for variable that will hold the size of these 550# minimum dimensions.551#552        ret_dsizes_names_str = ret_dsizes_names_str + ret_dsizes_names[j]553      if not ret_dsizes_names_str in global_dsizes_names: 554        global_dsizes_names.append(ret_dsizes_names_str)555      if not ret_dsizes_names_str in global_var_names: 556        global_var_names.append(ret_dsizes_names_str)557        global_var_types.append(ctypes.index('int'))558        global_calling_char.append("&")559#560# With this information, create an instance of the Argument class for561# the return value.562#563  ret_arg = Argument(-1,ret_name,ret_itype,False,ret_ndims,ret_dsizes,564                     ret_min_ndims,ret_dsizes_names,ret_dsizes_names_str,565                     ret_has_missing)566#567# Get information about how Fortran function is to be called and what568# types its input variables are.569#570valid = False571while not valid:572  rinput = raw_input('\nHow many input arguments are there for the Fortran routine ' + fortran_name + '? ')573  try:574    fnum_args = int(rinput)575    if fnum_args <= 0:576      print "Invalid number of dimensions for Fortran routine."577      print "There should be at least one dimension, reenter."578    else:579      valid = True580  except:581    print "Must enter an integer > 0, reenter."582#583# Loop through the Fortran arguments and get the name and type.584#585for i in range(fnum_args):586  print "What is the name of argument # " + str(i) + " ?"587  print "You can select one of these existing names, or supply your own."588  for j in range(len(global_var_names)):589    print "   ",j,":",global_var_names[j]590  rinput = raw_input()591  valid = False592  from_list = False593  while not valid:594    try:595      ii = int(rinput)596      if (ii >= 0) or (ii < len(global_var_names)):597        valid = True598        farg_names.append(global_var_names[ii])599        farg_cchar.append(global_calling_char[ii])600        from_list = True601      else:602        print "Invalid integer, reenter."603    except:604      farg_names.append(rinput)605      various_var_names.append(rinput)606      valid = True607      rinput = raw_input("Does an '&' need to be prepended when passing '" +\608                         rinput + "' to the Fortran routine? (y/n) [n] ")609      if (lower(rinput) == "y"):610        farg_cchar.append('&')611      else:612        farg_cchar.append('')613  valid = False614  while not valid:615    if from_list:616      farg_types.append(global_var_types[ii])617      valid = True618    else:619      print "What type is '" + farg_names[i] + "'? [1] "620      for j in range(len(ctypes)):621        print "   ",j,":",ctypes[j]622   623      rinput = raw_input()624      if rinput == "":625        farg_types.append(1)626        various_var_types.append(1)627        valid = True628      else:629        try:630          if (int(rinput) < 0) or (int(rinput) >= len(ctypes)):631            print "Invalid type, reenter."632          else:633            farg_types.append(int(rinput))634            various_var_types.append(int(rinput))635            valid = True636        except:637          print "Must enter an integer, reenter."638#639# Print information about each argument for debugging purposes.640#641if debug:642  for i in range(len(args)):643    print args[i]644  if isfunc:645    print ret_arg646#647# Open wrapper file and start writing to it, but first648# make sure this is acceptable.649#650print 'I will be creating the files ' + wrapper_name + 'W.c and ' + \651      'wrapper_' + ncl_name + '.c.'652print 'The contents of wrapper_' + ncl_name + '.c should be copied over to wrapper.c.'653okay = raw_input("Is this okay? (y/n) [y] ")654if (lower(okay) == "n"):655  print "Bye!"656  sys.exit()657#658# Open the files. The first one (w1file) is for actually wrapping the659# Fortran code, and the second one (w2file) is for registering the660# function or procedure. The second file is for temporary use only: you661# should copy its contents to "wrapper.c" where all the built-in 662# functions and procedures are registered.663#664w1file = open(wrapper_name+'W.c','w')665w2file = open('wrapper_' + wrapper_name+'.c','w')666#667# Start writing information to the main wrapper code.668#669#---------------------------------------------------------------------670#671# Write out the include files needed.672#673#---------------------------------------------------------------------674w1file.write('#include <stdio.h>\n')675w1file.write('#include "wrapper.h"\n\n')676#---------------------------------------------------------------------677#678# Write out prototype for Fortran routine.679#680#681#  extern void NGCALLF(xxx,XXX)(double *, int*, etc *);682#683#---------------------------------------------------------------------684w1file.write("extern void NGCALLF("+ lower(fortran_name) + "," +685             upper(fortran_name) + ")(")686for i in range(len(farg_types)):687  if i == 0:688    w1file.write(ctypes[farg_types[i]] + " *")689  else:690    w1file.write(", " + ctypes[farg_types[i]] + " *")691w1file.write(");\n\n")692#---------------------------------------------------------------------693#694# Write out first line of NCL wrapper routine.695#696# NhlErrorTypes wrf_rh(void) {697#698#---------------------------------------------------------------------699w1file.write("NhlErrorTypes " + ncl_nameW + "( void )\n{\n")700#---------------------------------------------------------------------701#702# Write out the declarations for the input argument variables.703#704#---------------------------------------------------------------------705w1file.write("""706/*707 * Input variables708 */709""")710#---------------------------------------------------------------------711#712# First write code to declare variable itself along with its type.713#714# Variables that are "void" will be converted to double715# precision, so they will have a "tmp_xxx" variable716# associated with them.717#718#---------------------------------------------------------------------719for i in range(len(args)):720  w1file.write("/*\n")721  w1file.write(" * Argument # " + str(i) + "\n")722  w1file.write(" */\n")723  w1file.write("  " + args[i].ctype + " *" + args[i].name + ";\n")724  if args[i].ntype == "numeric":725    w1file.write("  double *" + args[i].tmp_name + " = NULL;\n")726#---------------------------------------------------------------------727#728# Write out dimension information.729#730# int ndims_x, dsizes_x[...];731#732#---------------------------------------------------------------------733  if args[i].ndims == 0:734    w1file.write("  int       " + args[i].ndims_name + ";\n")735    w1file.write("  ng_size_t " + args[i].dsizes_name + \736                "[NCL_MAX_DIMENSIONS];\n")737  else:738#739# We only need to include the dimension sizes if one of the sizes740# is unknown (represented by being set to '0').741#742    if 0 in args[i].dsizes:743      w1file.write("  ng_size_t " + args[i].dsizes_name + "[" + str(args[i].ndims) + "];\n")744#---------------------------------------------------------------------745#746# Include missing value variables for each variable that can contain747# missing values. In addition, if the variable is numeric, be sure748# to create variables to hold the double and single versions of749# the missing value.750#751# int has_missing_x;752# NclScalar missing_x, missing_dbl_x, missing_flt_x;753#754#---------------------------------------------------------------------755  if args[i].has_missing:756    w1file.write("  int " + args[i].has_msg_name + ";\n")757    if args[i].ntype == "numeric":758      w1file.write("  NclScalar " + args[i].msg_name + ", " + \759                   args[i].msg_fname + ", " + args[i].msg_dname + ";\n")760    else:761      w1file.write("  NclScalar " + args[i].msg_name + ";\n")762#---------------------------------------------------------------------763#764# Include a type variable for each variable that is numeric.765#766# NclBasicDataTypes type_x;767#768#---------------------------------------------------------------------769  if args[i].ntype == "numeric":770    w1file.write("  NclBasicDataTypes " + args[i].type_name + ";\n\n")771if isfunc:772#---------------------------------------------------------------------773#774# Write out declarations for return variable information. Include a775# temporary variable if the output is to be numeric.776#777#---------------------------------------------------------------------778  w1file.write("/*\n")779  w1file.write(" * Return variable\n")780  w1file.write(" */\n")781  w1file.write("  " + ret_arg.ctype + " *" + ret_arg.name + ";\n")782  if ret_arg.ntype == "numeric":783    w1file.write("  double *" + ret_arg.tmp_name + " = NULL;\n")784#---------------------------------------------------------------------785#786# Write out dimension information.787#788#---------------------------------------------------------------------789  w1file.write("  int       " + ret_arg.ndims_name  + ";\n")790  w1file.write("  ng_size_t " + ret_arg.dsizes_name + ";\n")791#---------------------------------------------------------------------792#793# Include missing value variables for each variable that can contain794# missing values. In addition, if the variable is numeric, be sure795# to create variables to hold the double and single versions of796# the missing value.797#798# int has_missing_x;799# NclScalar missing_x, missing_dbl_x, missing_flt_x;800#801#---------------------------------------------------------------------802  if ret_arg.has_missing:803    w1file.write("  int " + ret_arg.has_msg_name + ";\n")804    if ret_arg.ntype == "numeric":805      w1file.write("  NclScalar " + ret_arg.msg_name + ", " + \806                   ret_arg.msg_fname + ", " + ret_arg.msg_dname + ";\n")807    else:808      w1file.write("  NclScalar " + ret_arg.msg_name + ";\n")809#---------------------------------------------------------------------810#811# Include a type variable.812#813#  NclBasicDataTypes type_ret_val;814#815#---------------------------------------------------------------------816  w1file.write("  NclBasicDataTypes " + ret_arg.type_name + ";\n\n")817#---------------------------------------------------------------------818#819# Write out code for other randome variables, like dimension sizes.820#821#---------------------------------------------------------------------822w1file.write("""823/*824 * Various825 */826""")827if global_dsizes_names != []:828  w1file.write("  int ")829#830# Write out the various dimension size variables we've been collecting831# into the global_dsizes_names array.832#833  for i in range(len(global_dsizes_names)):834    if i == (len(global_dsizes_names)-1):835      w1file.write(global_dsizes_names[i] + ";\n")836    else:837      w1file.write(global_dsizes_names[i] + ", ")838#---------------------------------------------------------------------839#840# For any variable that has leftmost dimensions, we need a corresponding841# "index_xxx" variable.842#843#---------------------------------------------------------------------844  w1file.write("  int ")845  for i in range(len(index_names)):846    if i == (len(index_names)-1):847      w1file.write(index_names[i] + ";\n")848    else:849      w1file.write(index_names[i] + ", ")850#851# Write out the various work arrays and extra arguments we have to852# pass into Fortran array.853#854if various_var_names != []:855  for i in range(len(various_var_names)):856    w1file.write("  " + ctypes[various_var_types[i]] + " " + \857                 various_var_names[i] + ";\n")858if work_array_names != []:859  for i in range(len(work_array_names)):860    w1file.write("  " + ctypes[work_array_types[i]] + " " + \861                 work_array_names[i] + ";\n")862#863# Write out integer variables that will hold the size of each work864# array. This will be the same name as the work array, with an "l"865# in front of it.866#867  w1file.write("  int ")868  for i in range(len(work_array_names)):869    if i == (len(work_array_names)-1):870      w1file.write("l" + work_array_names[i] + ";\n")871    else:872      w1file.write("l" + work_array_names[i] + ", ")873#---------------------------------------------------------------------874#875# If any input variable has leftmost dimensions, include that variable876# here.877#878#---------------------------------------------------------------------879if have_leftmost:880  if isfunc:881    w1file.write("  int i, ndims_leftmost, size_leftmost, size_output, ret;\n")882  else:883    w1file.write("  int i, ndims_leftmost, size_leftmost;\n")884else:885  if isfunc:  886    w1file.write("  int size_output;\n")887  888#---------------------------------------------------------------------889#890# Write the NclGetArg code for retrieving each argument from the891# NCL function call.892#893#---------------------------------------------------------------------894w1file.write("""895/*896 * Retrieve parameters.897 *898 * Note any of the pointer parameters can be set to NULL, which899 * implies you don't care about its value.900 */901""")902#903# Loop across input arguments and generate code that will904# retrieve them from the NCL script.905#906for i in range(len(args)):907  w1file.write("/*\n")908  w1file.write(" * Get argument # " + str(i) + "\n")909  w1file.write(" */\n")910  w1file.write("  " + args[i].name + " = (" + args[i].ctype + \911              "*)NclGetArgValue(\n")912  w1file.write("           " + str(i) + ",\n")913  w1file.write("           " + str(len(args)) + ",\n")914  if args[i].ndims == 0:915    w1file.write("           &" + args[i].ndims_name + ",\n")916  else:917    w1file.write("           NULL,\n")918  if (args[i].ndims == 0) or (0 in args[i].dsizes):919    w1file.write("           " + args[i].dsizes_name + ",\n")920  else:921    w1file.write("           NULL,\n")922#923# These are for the missing values.924#925  if args[i].has_missing:926    w1file.write("           &" + args[i].msg_name + ",\n")927    w1file.write("           &" + args[i].has_msg_name + ",\n")928  else:929    w1file.write("           NULL,\n")930    w1file.write("           NULL,\n")931  if args[i].ntype == "numeric":932    w1file.write("           &" + args[i].type_name + ",\n")933  else:934    w1file.write("           NULL,\n")935  w1file.write("           DONT_CARE);\n")936#---------------------------------------------------------------------937#938# Write out code for doing some minimal error checking on input939# variable sizes.  We only need to check variable sizes that are 940# not hard-wired to a specific size (like "2 x 3 x 4" versus 941# "nx x ny x nz").942#943#944# Also, if a variable is to contain leftmost dimensions, then we need945# to make sure that it meets the bare minimum requirements for number946# of rightmost dimensions.947#948#---------------------------------------------------------------------949  if args[i].min_ndims > 0:950    w1file.write("""951/*952 * Check dimension sizes.953 */954""")955    w1file.write("  if(" + args[i].ndims_name + " < " + \956                str(args[i].min_ndims) + ") {\n")957    if (args[i].min_ndims == 1):958      w1file.write(fatal_str + 'The ' + args[i].name + \959                  ' array must have at least one dimension");\n')960    else:961      w1file.write(fatal_str + 'The ' + args[i].name + \962                  ' array must have at least ' + str(args[i].min_ndims) + \963                  ' dimensions");\n')964    w1file.write(return_fatal_str)965    w1file.write('  }\n')966#967# Code for coercing missing values to float and/or double.968#969  if args[i].has_missing and args[i].ntype == "numeric":970    w1file.write("""971/*972 * Coerce missing value to double if necessary.973 */974""")975    w1file.write("  coerce_missing(" + args[i].type_name + "," + \976                 args[i].has_msg_name + ",&" + args[i].msg_name + \977                 ",\n                 &" + args[i].msg_dname + ",&" + \978                 args[i].msg_fname + ");\n\n")979  if not args[i].is_scalar:980    dstr = ""981    for j in range(len(args[i].dsizes_names)):982#983# If we're not dealing with a scalar, then write the code that 984# assigns the size of the rightmost dimensions, and then creates985# a variable that will contain the size of all the rightmost dimensions.986#987# For example, if the rightmost dimensions are nx, ny, and988# nz, then the code will be "nxnynz = nx * ny * nz". 989#990      if not args[i].dsizes_names[j] in global_dsizes_names_accum:991        if args[i].ndims > 0:992          if args[i].dsizes[j] == 0:993            w1file.write('  ' + args[i].dsizes_names[j] + ' = ' + \994                         args[i].dsizes_name + '[' + str(j) + '];\n')995          else:996            w1file.write('  ' + args[i].dsizes_names[j] + ' = ' + \997                         str(args[i].dsizes[j]) + ';\n')998        else:999          w1file.write('  ' + args[i].dsizes_names[j] + ' = ' + \1000                      args[i].dsizes_name + '[' + args[i].ndims_name + '-' + 1001                      str(int(args[i].min_ndims-j)) + '];\n')1002        global_dsizes_names_accum.append(args[i].dsizes_names[j])1003      else:1004        if args[i].ndims > 0 and args[i].dsizes[j] == 0:1005          w1file.write('  if(' + args[i].dsizes_name + '[' + str(j) + \1006                       '] != ' + args[i].dsizes_names[j] + ') {\n')1007          w1file.write(fatal_str + 'The #' + str(j) + \1008                       ' dimension of ' + args[i].name + \1009                       ' must be length ' + args[i].dsizes_names[j] + \1010                       '");\n')1011        elif args[i].ndims == 0:1012          w1file.write('  if(' + args[i].dsizes_name + '[' + 1013                      args[i].ndims_name + '-' + str(args[i].min_ndims-j) + \1014                      '] != ' + args[i].dsizes_names[j] + ') {\n')1015          w1file.write(fatal_str + \1016                       'The ndims-' + str(int(args[i].min_ndims-j)) + \1017                       ' dimension of ' + args[i].name + \1018                       ' must be of length ' + args[i].dsizes_names[j] + \1019                       '");\n')1020        w1file.write(return_fatal_str)1021        w1file.write('  }\n')1022      if args[i].min_ndims > 1 or args[i].ndims > 1:1023        if j == 0:1024          dstr = "  " + args[i].dsizes_names_str + " = " + \1025                 args[i].dsizes_names[0]1026        else:1027          dstr = dstr + " * " + args[i].dsizes_names[j]1028    if dstr != "":1029      w1file.write(dstr + ";\n\n")1030#---------------------------------------------------------------------1031#1032# Write out code to calculate size of leftmost dimensions, if any.1033#1034#---------------------------------------------------------------------1035if have_leftmost:1036  first    = True1037  name_str = ""1038  w1file.write("""1039/*1040 * Calculate size of leftmost dimensions.1041 */1042""")1043  w1file.write("  size_leftmost  = 1;\n")1044  for i in range(len(args)):1045    if args[i].min_ndims > 0:1046      if first:1047        w1file.write("  ndims_leftmost = " + args[i].ndims_name + "-" + 1048                     str(args[i].min_ndims) + ";\n");1049        w1file.write("  for(i = 0; i < ndims_leftmost; i++) {\n")1050        first_arg_name = args[i].name       # Keep track of this argument1051        prev_arg_name  = first_arg_name1052        first          = False1053        second         = True1054      else:1055        if second:1056          w1file.write("    if(" + args[i].dsizes_name + "[i] != dsizes_" + \1057                       first_arg_name + "[i]")1058          name_str      = prev_arg_name1059          prev_arg_name = args[i].name1060          second        = False1061        else:1062          name_str = name_str + ", " + prev_arg_name1063          w1file.write(" ||\n       " + args[i].dsizes_name + \1064                      "[i] != dsizes_" + first_arg_name + "[i]")1065          prev_arg_name = args[i].name1066#---------------------------------------------------------------------1067#1068# Write code to close leftmost dimensions loop.1069#1070#---------------------------------------------------------------------1071  if name_str != "":1072    w1file.write(") {\n")1073    w1file.write('  ' + fatal_str + 'The leftmost dimensions of ' + \1074                 name_str + ' and ' + prev_arg_name + \1075              ' must be the same");\n')1076    w1file.write('  ' + return_fatal_str)1077    w1file.write('    }\n')1078  if not first:1079    w1file.write("    size_leftmost *= dsizes_" + first_arg_name + "[i];\n")1080    w1file.write("  }\n\n")1081#---------------------------------------------------------------------1082#1083# Write out code to allocate space for coercing input arrays, if any of1084# them are numeric.  In addition, if the number of dimensions is unknown,1085# then we need to allocate space for the temporary array, and later1086# it will be coerced.1087#1088#---------------------------------------------------------------------1089first = True1090for i in range(len(args)):1091  name = args[i].name1092  if args[i].ntype == "numeric":1093    if first:1094      first = False1095      if isfunc and ret_arg.ntype == "numeric":1096#---------------------------------------------------------------------1097# While we're here, we can also set the output array type, based1098# on whether any of the input is double or not.1099#---------------------------------------------------------------------1100        w1file.write("""1101/*1102 * The output type defaults to float, unless this input array is double.1103 */1104""")1105        w1file.write("  " + ret_arg.type_name + " = NCL_float;\n")1106      w1file.write("""1107/* 1108 * Allocate space for coercing input arrays.  If any of the input1109 * is already double, then we don't need to allocate space for1110 * temporary arrays, because we'll just change the pointer into1111 * the void array appropriately.1112 */1113""")1114#---------------------------------------------------------------------1115# If input is not already double, then we'll need to allocate a1116# temporary array to coerce it to double.1117#---------------------------------------------------------------------1118    w1file.write("/*\n")1119    w1file.write(" * Allocate space for " + args[i].tmp_name + ".\n")1120    w1file.write(" */\n")1121    if args[i].min_ndims > 0:1122#1123# We are dealing with an array that has possible leftmost dimensions.1124#1125      w1file.write("  if(" + args[i].type_name + " != NCL_double) {\n")1126      w1file.write("    " + args[i].tmp_name + " = (double *)calloc(" + \1127                  args[i].dsizes_names_str + ",sizeof(double));\n")1128      w1file.write("    if(" + args[i].tmp_name + " == NULL) {\n")1129      w1file.write('  ' + fatal_str + \1130                  'Unable to allocate memory for coercing input array to double");\n')1131      w1file.write("  " + return_fatal_str)1132      w1file.write("    }\n")1133      w1file.write("  }\n")1134    else:1135#1136# This array has no leftmost dimensions, so go ahead and coerce it1137# to double here. We have two separate cases, depending on whether1138# the input can contain a missing value.1139#1140      if args[i].is_scalar:1141        size = "1"1142      else:1143        size = args[i].dsizes_names_str1144      if args[i].has_missing:1145        w1file.write("  " + args[i].tmp_name + " = coerce_input_double(" + \1146                     name + "," + args[i].type_name + "," + size + "," + \1147                     args[i].has_msg_name + ",&" + args[i].msg_name + ",&" + \1148                     args[i].msg_dname + ");\n")1149      else:1150        w1file.write("  " + args[i].tmp_name + " = coerce_input_double(" + \1151                     name + "," + args[i].type_name + "," + size + "," + \1152                     "0,NULL,NULL);\n")1153      w1file.write("  if(" + args[i].tmp_name + " == NULL) {\n")1154      w1file.write(fatal_str + \1155                  'Unable to allocate memory for coercing input array to double");\n')1156      w1file.write(return_fatal_str)1157      w1file.write("  }\n")1158    if isfunc and ret_arg.ntype == "numeric" and args[i].sets_otype:1159#---------------------------------------------------------------------1160# If this input argument is numeric, and its one whose type determines1161# the output for the output, then include the code for that here.1162#---------------------------------------------------------------------1163      w1file.write("  else {\n")1164      w1file.write("    " + ret_arg.type_name + " = NCL_double;\n")1165      w1file.write("  }\n")1166#---------------------------------------------------------------------1167# Code to handle allocating space for output array and its dimension1168# sizes. Also, we may have to allocate a temporary array to hold space1169# for a double array, if the return value is not double.1170#---------------------------------------------------------------------1171if isfunc:1172#----------------------------------------------------------------------1173# Code to calculate size of output array.1174#----------------------------------------------------------------------1175  w1file.write("""1176/*1177 * Calculate size of output array.1178 */1179""")1180#1181# Create string that will hold total dimension sizes of rightmost1182# dimensions of return variable.1183#1184  if not ret_arg.is_scalar:1185    if (ret_arg.min_ndims > 0) or (0 in ret_arg.dsizes):1186      if ret_arg.min_ndims > 1 or ret_arg.ndims > 1:1187        for j in range(len(ret_arg.dsizes_names)):1188          if j == 0:1189            ret_dstr = "  " + ret_arg.dsizes_names_str + " = " + \1190                       ret_arg.dsizes_names[0]1191          else:1192            ret_dstr = ret_dstr + " * " + ret_arg.dsizes_names[j]1193        w1file.write(ret_dstr + ";\n")1194    w1file.write("  size_output = size_leftmost * " + \1195                ret_arg.dsizes_names_str + ";\n")1196  else:1197    w1file.write("  size_output = ...need input here...;\n")1198  w1file.write("""1199/* 1200 * Allocate space for output array.1201 */1202""")1203  if ret_arg.ntype == "numeric":1204    w1file.write("  if(" + ret_arg.type_name + " != NCL_double) {\n")1205    w1file.write("    " + ret_arg.name + " = (void *)calloc(size_output, " + \1206                  "sizeof(float));\n")1207    if ret_arg.min_ndims > 0:1208      w1file.write("    " + ret_arg.tmp_name + " = (double *)calloc(" + \1209                  ret_arg.dsizes_names_str + ",sizeof(double));\n")1210    else:1211      w1file.write("    " + ret_arg.tmp_name + \1212        " = (double *)calloc(...need input here...,sizeof(double));\n")1213    w1file.write("    if(" + ret_arg.tmp_name + " == NULL) {\n")1214    w1file.write('  ' + fatal_str + \1215                'Unable to allocate memory for temporary output array");\n')1216    w1file.write("  " + return_fatal_str)1217    w1file.write("    }\n")1218    w1file.write("  }\n")1219    w1file.write("  else {\n")1220    w1file.write("    " + ret_arg.name + " = (void *)calloc(size_output, " + \1221                  "sizeof(double));\n")1222    w1file.write("  }\n")1223  else :1224    w1file.write("    " + ret_arg.name + " = (" + ret_arg.ctype + \1225                "*)calloc(size_output, sizeof(" + ret_arg.ctype + "));\n")1226  w1file.write("  if(" + ret_arg.name + " == NULL) {\n")1227  w1file.write(fatal_str + 'Unable to allocate memory for output array");\n')1228  w1file.write(return_fatal_str)1229  w1file.write("  }\n")1230#1231# Set the missing value for the output, if any.1232#1233  if ret_has_missing and (num_input_has_missing > 0) and ret_msg_depend_input:1234    w1file.write("  if(" + args[ret_msg_depend_index].has_msg_name + ") {\n")1235    w1file.write("    if(" + ret_arg.type_name + " == NCL_double) " + \1236                 ret_arg.msg_name + " = " + \1237                 args[ret_msg_depend_index].msg_dname + ";\n")1238    w1file.write("    else                 " + ret_arg.msg_name + " = " + \1239                 args[ret_msg_depend_index].msg_fname + ";\n")1240    w1file.write("    " + ret_arg.msg_dname + " = " + \1241                 args[ret_msg_depend_index].msg_dname + ";\n")1242    w1file.write("  }\n")1243  w1file.write("""1244/* 1245 * Allocate space for output dimension sizes and set them.1246 */1247""")1248  if ret_arg.ndims > 0:1249    w1file.write("  " + ret_arg.ndims_name + " = " + str(ret_arg.ndims) + ";\n")1250  else:1251    w1file.write("  " + ret_arg.ndims_name + " = ndims_leftmost + " + \1252                str(ret_arg.min_ndims) + ";\n")1253  w1file.write("  " + ret_arg.dsizes_name + " = (ng_size_t*)calloc(" + \1254              ret_arg.ndims_name + ",sizeof(ng_size_t));  \n")1255  w1file.write("  if( " + ret_arg.dsizes_name + " == NULL ) {\n")1256  w1file.write(fatal_str + \1257               'Unable to allocate memory for holding dimension sizes");\n')1258  w1file.write(return_fatal_str)1259  w1file.write("  }\n")1260  if ret_arg.min_ndims > 0:1261#1262# Loop through input arguments until we find one that has leftmost1263# dimensions, and then use its leftmost dimensions to assign 1264# dimensions to the output array's dimension sizes array.1265#1266    for i in range(len(args)):1267      if args[i].min_ndims > 0:1268        w1file.write("  for(i = 0; i < " + ret_arg.ndims_name + "-" + \1269                    str(ret_arg.min_ndims) + "; i++) " + \1270                    ret_arg.dsizes_name + "[i] = " + args[i].dsizes_name + "[i];\n")1271        break1272    else:1273      w1file.write("  for(i = 0; i < " + ret_arg.ndims_name + \1274                  "; i++)" + ret_arg.dsizes_name + \1275                  "[i] = ...need input here;\n")1276    for i in range(ret_arg.min_ndims):1277      w1file.write("  " + ret_arg.dsizes_name + "[" + ret_arg.ndims_name + 1278                  "-" + str(ret_min_ndims-i) + "] = " + \1279                  ret_dsizes_names[i] + ";\n")1280  else:1281    w1file.write("  for(i = 0; i < " + ret_arg.ndims_name + "; i++)" + \1282                 ret_arg.dsizes_name + "[i] = ...need input here;\n")1283#1284# Write out code for the loop across leftmost dimensions (if any).1285#1286if have_leftmost:1287  w1file.write("""1288/*1289 * Loop across leftmost dimensions and call the Fortran routine for each1290 * subsection of the input arrays.1291 */1292""")1293  index_str = "  "1294  for i in range(len(index_names)):1295    if i < (len(index_names)-1):1296      index_str = index_str + index_names[i] + " = "1297    else:1298      index_str = index_str + index_names[i] + " = 0;\n"1299  w1file.write(index_str)1300  w1file.write("\n  for(i = 0; i < size_leftmost; i++) {\n")1301  for i in range(len(args)):1302    name = args[i].name1303    if args[i].ntype == "numeric" and args[i].ndims == 0:1304      w1file.write("/*\n")1305      w1file.write(" * Coerce subsection of " + name + " (" + \1306                  args[i].tmp_name + ") to double if necessary.\n")1307      w1file.write(" */\n")1308      w1file.write("    if(" + args[i].type_name + " != NCL_double) {\n")1309      w1file.write("      coerce_subset_input_double(" + name + "," + \1310                   args[i].tmp_name + "," + args[i].index_name + "," + \1311                   args[i].type_name + "," + args[i].dsizes_names_str + \1312                   ",0,NULL,NULL);\n")1313      w1file.write("    }\n")1314      w1file.write("    else {\n")1315      w1file.write("      " + args[i].tmp_name + " = &((double*)" + name + \1316                  ")[" + args[i].index_name + "];\n")1317      w1file.write("    }\n\n")1318#1319# Write out code for pointing temporary output array to appropriate1320# location in output array, if necessary.1321#1322  if isfunc and ret_arg.ntype == "numeric" and ret_arg.ndims == 0:1323    w1file.write("""1324/*1325 * Point temporary output array to void output array if appropriate.1326 */1327""")1328    w1file.write("    if(" + ret_arg.type_name + " == NCL_double) " + \1329                ret_arg.tmp_name + " = &((double*)" + ret_arg.name + \1330                ")[" + ret_arg.index_name + "];\n\n")1331#1332# Write code for calling Fortran routine inside loop.1333#1334  w1file.write("""1335/*1336 * Call the Fortran routine.1337 */1338""")1339  w1file.write("    NGCALLF("+ lower(fortran_name) + "," + \1340              upper(fortran_name) + ")(")1341  for i in range(len(farg_names)):1342    if i == 0:1343      w1file.write(farg_cchar[i] + farg_names[i])1344    else:1345      w1file.write(", " + farg_cchar[i] + farg_names[i])1346  w1file.write(");\n")1347#1348# Code for copying values back to void array, if the output is1349# supposed to be float.1350#1351  if isfunc and ret_arg.ntype == "numeric":1352    w1file.write("""1353/*1354 * Coerce output back to float if necessary.1355 */1356""")1357    w1file.write("    if(" + ret_arg.type_name + " == NCL_float) {\n")1358    w1file.write("      coerce_output_float_only(" + ret_arg.name + \1359                "," + ret_arg.tmp_name + "," + ret_arg.dsizes_names_str + \1360                "," + ret_arg.index_name + ");\n")1361    w1file.write("    }\n")1362#1363# Write out code for incrementing index variables, if any.1364#1365  for i in range(len(args)):1366    if args[i].ntype == "numeric" and args[i].ndims == 0:1367      w1file.write("    "  + args[i].index_name + " += " + \1368                  args[i].dsizes_names_str + ";\n")1369  if isfunc and ret_arg.ntype == "numeric" and ret_arg.ndims == 0:1370    w1file.write("    "  + ret_arg.index_name + " += " + \1371                ret_arg.dsizes_names_str + ";\n")1372  w1file.write("  }\n")    # End "for" loop1373else:1374#1375# We are dealing with a function that doesn't have any arguments1376# with leftmost dimensions. This is unusual, but possible.1377#1378# Write code for calling Fortran routine not in a loop.1379#1380  w1file.write("""1381/*1382 * Call the Fortran routine.1383 */1384""")1385  w1file.write("  NGCALLF("+ lower(fortran_name) + "," + \1386              upper(fortran_name) + ")(")1387  for i in range(len(farg_names)):1388    if i == 0:1389      w1file.write(farg_names[i])1390    else:1391      w1file.write(", " + farg_names[i])1392  w1file.write(");\n")1393#1394# Set up code for freeing unneeded memory.  Only those input variables1395# that had to be coerced to double precision need to be freed.1396#1397first = True1398for i in range(len(args)):1399  if args[i].ntype == "numeric":1400#1401# Write code for calling Fortran routine not in a loop.1402#1403    if first:1404      w1file.write("""1405/*1406 * Free unneeded memory.1407 */1408""")1409      first = False1410    w1file.write("  if(" + args[i].type_name + \1411                " != NCL_double) NclFree(" + args[i].tmp_name + ");\n")1412if isfunc and ret_arg.ntype == "numeric":1413  w1file.write("  if(" + ret_arg.type_name + \1414              " != NCL_double) NclFree(" + ret_arg.tmp_name + ");\n")1415#1416# Set up code for returning information back to NCL script.1417#1418if isfunc:1419  w1file.write("""1420/*1421 * Return value back to NCL script.1422 */1423""")1424#1425# If the return can have a missing value, account for it here. Also,1426# if the return can be float or double, then we have to return1427# the correct missing value.1428#1429  if ret_has_missing:1430    if ret_arg.ntype == "numeric":1431      w1file.write("  if(" + ret_arg.type_name + " != NCL_double) {\n")1432      w1file.write("    ret = NclReturnValue(" + ret_arg.name + "," + \1433                   ret_arg.ndims_name + "," + ret_arg.dsizes_name + \1434                   ",&" + ret_arg.msg_fname + "," + \1435                   ret_arg.type_name + ",0);\n")1436      w1file.write("  }\n")1437      w1file.write("  else {\n")1438      w1file.write("    ret = NclReturnValue(" + ret_arg.name + "," + \1439                   ret_arg.ndims_name + "," + ret_arg.dsizes_name + \1440                   ",&" + ret_arg.msg_dname + "," + \1441                   ret_arg.type_name + ",0);\n")1442      w1file.write("  }\n")1443    else:1444      w1file.write("  else {\n")1445      w1file.write("    ret = NclReturnValue(" + ret_arg.name + "," + \1446                   ret_arg.ndims_name + "," + ret_arg.dsizes_name + "," + \1447                   ret_arg.msg_name + "," + ret_arg.type_name + ",0);\n")1448      w1file.write("  }\n")1449  else:1450    w1file.write("  ret = NclReturnValue(" + ret_arg.name + "," + \1451                ret_arg.ndims_name + "," + ret_arg.dsizes_name + ",NULL," + \1452                ret_arg.type_name + ",0);\n")1453  w1file.write("  NclFree(" + ret_arg.dsizes_name + ");\n")1454  w1file.write("  return(ret);\n")1455else:1456  w1file.write("""1457/*1458 * This is a procedure, so no values are returned.1459 */1460""")1461  w1file.write("  return(NhlNOERROR);\n")1462#---------------------------------------------------------------------1463#1464# Write out last line of NCL wrapper routine.1465#1466# }1467#1468#---------------------------------------------------------------------1469w1file.write("}\n")1470#1471# Write the code for registering this function or procedure with NCL.1472# This will be written to a different file, and needs to be copied1473# to "wrapper.c".1474#1475w2file.write('extern NhlErrorTypes ' + ncl_nameW + '(void);\n')1476w2file.write('/*\n * Register "' + ncl_name + '".\n *\n')1477w2file.write(' * Create private argument array\n */\n')1478w2file.write('        nargs = 0;\n')1479w2file.write('        args = NewArgs(' + str(num_args) + ');\n\n')1480for i in range(num_args):1481  if args[i].ndims == 0:1482    w2file.write('        SetArgTemplate(args,nargs,"' + args[i].ntype + \1483                 '",0,NclANY);nargs++;\n')1484  else:1485    for j in range(args[i].ndims):1486      w2file.write('        dimsizes[' + str(j) + '] = ' + \1487                   str(args[i].dsizes[j]) + ';\n')1488    w2file.write('        SetArgTemplate(args,nargs,"' + args[i].ntype + \1489                 '",' + str(args[i].ndims) + ',dimsizes);nargs++;\n')1490if isfunc:1491  w2file.write('\n        NclRegisterFunc(' + ncl_nameW + ',args,"' + \1492               ncl_name + '",nargs);\n')1493else:1494  w2file.write('\n        NclRegisterProc(' + ncl_nameW + ',args,"' + \1495               ncl_name + '",nargs);\n')1496#1497# Close files.1498#1499w1file.close()...rui.py
Source:rui.py  
1#this file is the rui script of 5010, inludes bg96 and other sensors.2#use ampy --port /dev/ttyACM0 put rui.py to your board34import time5import math6from machine import Pin7from machine import UART8from machine import I2C910i2c=I2C(1, 13, 14)11uart=UART(0, 115200)1213def get_acceleration(echo=False, ret=True):14  x_l=i2c.readfrom_mem(0x19, 0x28, 1)15  x_h=i2c.readfrom_mem(0x19, 0x29, 1)16  y_l=i2c.readfrom_mem(0x19, 0x2a, 1)17  y_h=i2c.readfrom_mem(0x19, 0x2b, 1)18  z_l=i2c.readfrom_mem(0x19, 0x2c, 1)19  z_h=i2c.readfrom_mem(0x19, 0x2d, 1)20  x= (x_h[0]<<8) | x_l[0]21  y= (y_h[0]<<8) | y_l[0]22  z= (z_h[0]<<8) | z_l[0]23  if x < 0x8000:24    x=x25  else:26    x=x-0x1000027  if y < 0x8000:28    y=y29  else:30    y=y-0x1000031  if z < 0x8000:32    z=z33  else:34    z=z-0x1000035  acc_x=(x*4000)/65536.036  acc_y=(y*4000)/65536.037  acc_z=(z*4000)/65536.038  echo_Arg='lis3dh: acc_x='+str(acc_x)+', acc_y='+str(acc_y)+', acc_z='+str(acc_z)39  ret_Arg={}40  ret_Arg['x']=acc_x41  ret_Arg['y']=acc_y42  ret_Arg['z']=acc_z43  return _answer(echo, ret, echo_Arg, ret_Arg)4445def get_light_strength(echo=False, ret=True):46  buf=i2c.readfrom_mem(0x44, 0x00, 2)47  light=int.from_bytes(buf, 'big')48  m=light & 0x0FFF49  e=(light & 0xF000) >> 1250  h= math.pow(2, e)51  light = m*(0.01 * h)52  echo_Arg='opt3001: Light strength = '+str(light)53  ret_Arg=light54  return _answer(echo, ret, echo_Arg, ret_Arg)5556def get_temperature_humidity(echo=False, ret=True):57  buf=bytearray([0x7C, 0xA2])58  i2c.writeto(0x70, buf)59  buf2=bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00])60  i2c.readfrom_into(0x70, buf2)61  temp = (buf2[1] | (buf2[0] << 8)) * 175 / 65536.0 - 45.062  humi = (buf2[4] | (buf2[3] << 8)) * 100 / 65536.063  echo_Arg='shtc3: Temperature='+str(temp)+', Humidity='+str(humi)64  ret_Arg={}65  ret_Arg['temp']=temp66  ret_Arg['humi']=humi67  return _answer(echo, ret, echo_Arg, ret_Arg)6869def get_pressure(echo=False, ret=True):70  pre_xl=i2c.readfrom_mem(0x5c, 0x28, 1)71  pre_xl=int.from_bytes(pre_xl, 'big')72  pre_l=i2c.readfrom_mem(0x5c, 0x29, 1)73  pre_l=int.from_bytes(pre_l, 'big')74  pre_h=i2c.readfrom_mem(0x5c, 0x2a, 1)75  pre_h=int.from_bytes(pre_h, 'big')76  pre = (pre_h<<16)|(pre_l<<8)|pre_xl77  if pre & 0x00800000:78    pre |= 0xFF00000079  pre = pre/4096.080  echo_Arg='lps22hb: Pressure='+str(pre)+' HPa'81  ret_Arg=pre82  return _answer(echo, ret, echo_Arg, ret_Arg)8384def get_gps(echo=False, ret=True):85  buf=bytearray()86  uart.write('AT+QGPSCFG=\"gpsnmeatype\", 1')87  time.sleep_ms(10)88  bchar=uart.readchar()89  while bchar != -1:90    buf.append(bchar)91    bchar=uart.readchar()92    time.sleep_ms(1)93  buf2=bytearray()94  uart.write('AT+QGPS=1, 1, 1, 1, 1')95  time.sleep_ms(10)96  bchar=uart.readchar()97  while bchar != -1:98    buf2.append(bchar)99    bchar=uart.readchar()100    time.sleep_ms(1)101  buf3=bytearray()102  uart.write('AT+QGPSGNMEA=\"GGA\"')103  time.sleep_ms(10)104  bchar=uart.readchar()105  while bchar != -1:106    buf3.append(bchar)107    bchar=uart.readchar()108    time.sleep_ms(1)109  string = str(buf3, 'utf-8')110  return _answer(echo, ret, string, string)111112#this function is suitable for most AT commands of bg96. Timeout(ms) is what bg96 needs depending on the AT. e.g. rui.cellular_tx('ATI', 500)113def cellular_tx(at, timeout=500, echo=True, ret=False):114  """Improved command. Added two variables:115   . echo: should we print the result?116   . ret:  should we return the result as a string?117   This later feature is used by some functions below to display info in a better format."""118  buf3=bytearray()119  uart.write(at)120  time.sleep_ms(10)121  bchar=uart.readchar()122  while (bchar != -1) or (timeout > 0):123    if bchar != -1:124      buf3.append(bchar)125    bchar=uart.readchar()126    timeout=timeout-1127    time.sleep_ms(1)128  string = str(buf3, 'utf-8')129  return _answer(echo, ret, string, string)130  ## Using this string in gnss_get_nmea() for instance, to extract data.131132### Contribution by Kongduino133134_bg96_errors={}135_bg96_errors[0]="Phone failure"136_bg96_errors[1]="No connection to phone"137_bg96_errors[2]="Phone-adaptor link reserved"138_bg96_errors[3]="Operation not allowed"139_bg96_errors[4]="Operation not supported"140_bg96_errors[5]="PH-SIM PIN required"141_bg96_errors[6]="PH-FSIM PIN required"142_bg96_errors[7]="PH-FSIM PUK required"143_bg96_errors[10]="(U)SIM not inserted"144_bg96_errors[11]="(U)SIM PIN required"145_bg96_errors[12]="(U)SIM PUK required"146_bg96_errors[13]="(U)SIM failure"147_bg96_errors[14]="(U)SIM busy"148_bg96_errors[15]="(U)SIM wrong"149_bg96_errors[16]="Incorrect password"150_bg96_errors[17]="(U)SIM PIN2 required"151_bg96_errors[18]="(U)SIM PUK2 required"152_bg96_errors[20]="Memory full"153_bg96_errors[21]="Invalid index"154_bg96_errors[22]="Not found"155_bg96_errors[23]="Memory failure"156_bg96_errors[24]="Text string too long"157_bg96_errors[25]="Invalid characters in text string"158_bg96_errors[26]="Dial string too long"159_bg96_errors[27]="Invalid characters in dial string"160_bg96_errors[30]="No network service"161_bg96_errors[31]="Network timeout"162_bg96_errors[32]="Network not allowed - emergency calls only"163_bg96_errors[40]="Network personalization PIN required"164_bg96_errors[41]="Network personalization PUK required"165_bg96_errors[42]="Network subset personalization PIN required"166_bg96_errors[43]="Network subset personalization PUK required"167_bg96_errors[44]="Service provider personalization PIN required"168_bg96_errors[45]="Service provider personalization PUK required"169_bg96_errors[46]="Corporate personalization PIN required"170_bg96_errors[47]="Corporate personalization PUK required"171_bg96_errors[300]="ME failure"172_bg96_errors[301]="SMS ME reserved"173_bg96_errors[302]="Operation not allowed"174_bg96_errors[303]="Operation not supported"175_bg96_errors[304]="Invalid PDU mode"176_bg96_errors[305]="Invalid text mode"177_bg96_errors[310]="(U)SIM not inserted"178_bg96_errors[311]="(U)SIM pin necessary"179_bg96_errors[312]="PH (U)SIM pin necessary"180_bg96_errors[313]="(U)SIM failure"181_bg96_errors[314]="(U)SIM busy"182_bg96_errors[315]="(U)SIM wrong"183_bg96_errors[316]="(U)SIM PUK required"184_bg96_errors[317]="(U)SIM PIN2 required"185_bg96_errors[318]="(U)SIM PUK2 required"186_bg96_errors[320]="Memory failure"187_bg96_errors[321]="Invalid memory index"188_bg96_errors[322]="Memory full"189_bg96_errors[330]="SMSC address unknown"190_bg96_errors[331]="No network"191_bg96_errors[332]="Network timeout"192_bg96_errors[501]="Invalid parameter"193_bg96_errors[502]="Operation not supported"194_bg96_errors[503]="GNSS subsystem busy"195_bg96_errors[504]="Session is ongoing"196_bg96_errors[505]="Session not active"197_bg96_errors[506]="Operation timeout"198_bg96_errors[507]="Function not enabled"199_bg96_errors[508]="Time information error"200_bg96_errors[509]="XTRA not enabled"201_bg96_errors[512]="Validity time is out of range"202_bg96_errors[513]="Internal resource error"203_bg96_errors[514]="GNSS locked"204_bg96_errors[515]="End by E911"205_bg96_errors[516]="Not fixed now"206_bg96_errors[517]="Geo-fence ID does not exist"207_bg96_errors[549]="Unknown error"208209def _answer(echo, ret, echo_Arg, ret_Arg):210  if(echo):211    print(echo_Arg)212  if(ret):213    return ret_Arg214215def gnss_on(mode=1, fixmaxtime=30, fixmaxdist=50, fixcount=0, fixrate=1, echo=True, ret=False):216  """217  Turns on the GNSS function218  Default parameters219  Checks parameters before sending, or fails.220  """221  if(mode<1) or (mode>4):222    print("GNSS working mode range 1<>4!")223    print("Default is 1.")224    print("""    1 Stand-alone225    2 MS-based226    3 MS-assisted227    4 Speed-optimal""")228    return229  if(fixmaxtime<1) or (fixmaxtime>255):230    print("Maximum positioning time range 1<>255!")231    print("Default is 30 seconds.")232    return233  if(fixmaxdist<1) or (fixmaxdist>1000):234    print("Accuracy threshold of positioning range 1<>1000!")235    print("Default is 50 meters.")236    return237  if(fixcount>1000):238    print("Number of attempts for positioning range 0<>1000!")239    print("Default is 0 (continuous).")240    return241  if(fixrate<1) or (fixrate>65535):242    print("Interval between first and second positioning range 1<>65535!")243    print("Default is 1 second.")244    return245  result=cellular_tx('AT+QGPS='+str(mode)+','+str(fixmaxtime)+','+str(fixmaxdist)+','+str(fixcount)+','+str(fixrate), 500, False, True).replace('\r', '').strip()246  return _answer(echo, ret, result, result)247248def gnss_off(echo=True, ret=False):249  """Turns off GNSS"""250  result=cellular_tx('AT+QGPSEND', 500, False, True).replace('\r', '').strip()251  return _answer(echo, ret, result, result)252253def gnss_status(echo=True, ret=False):254  """Enquires GNSS status"""255  result=cellular_tx('AT+QGPS?', 500, False, True).replace('\r', '').strip()256  if(result.startswith('AT+QGPS?\n+QGPS: ')):257    #Correct result258    a=result.split(': ')[1].split('\n')[0]259    if(a=='0'):260      echo_Arg="GNSS OFF"261    if(a=='1'):262      echo_Arg="GNSS ON"263    ret_Arg=echo_Arg264  else:265    echo_Arg="Unknown result response:\n  "+result266    ret_Arg={}267  return _answer(echo, ret, echo_Arg, ret_Arg)268269def gpsloc(mode=0, echo=False, ret=True):270  """Acquire Positioning Information271  Modes:272    0: <latitude>,<longitude> format: ddmm.mmmm N/S,dddmm.mmmm E/W273    1: <latitude>,<longitude> format: ddmm.mmmmmm N/S,dddmm.mmmmmm E/W274    2: <latitude>,<longitude> format: (-)dd.ddddd,(-)ddd.ddddd275    Checks mode"""276  if(mode<0) or (mode>2):277    print("GPSLOC mode range 0<>2!")278    print("Default is 0.")279    print("""    Modes:280    0: <latitude>,<longitude> format: ddmm.mmmm N/S,dddmm.mmmm E/W281    1: <latitude>,<longitude> format: ddmm.mmmmmm N/S,dddmm.mmmmmm E/W282    2: <latitude>,<longitude> format: (-)dd.ddddd,(-)ddd.ddddd""")283    return284  result=cellular_tx('AT+QGPSLOC='+str(mode), 500, False, True).replace('\r', '').strip()285  if(result.find('\n+CME ERROR: ')>-1):286    #'AT+QGPSLOC=0\n+CME ERROR: 516'287    a=int(result.split(': ')[1].split('\n')[0].split(',')[0])288    ret_Arg={}289    ret_Arg['code']=a290    ret_Arg['text']=_bg96_errors[a]291  if(result.find('\n+QGPSLOC: ')>-1):292    #+QGPSLOC: <UTC>,<latitude>,<longitude>,<hdop>,<altit ude>,<fix>,<cog>,<spkm>,<spkn>,<date>,<nsat>293    #we have a match294    a=result.split(': ')[1].split('\n')[0].split(',')295    ret_Arg={}296    time=a[0].split('.')[0]297    ret_Arg['tof']=time[0:2]+':'+time[2:4]+':'+time[4:]+' UTC'298    NS="N"299    EW="E"300    if(mode==2):301      #long/lat format [-]dd.ddddd302      if(a[1][0:1]=='-'):303        NS="S"304        a[1]=a[1][1:]305      if(a[2][0:1]=='-'):306        EW="W"307        a[2]=a[2][1:]308    else:309      #long/lat format ddmm.mmmm[mm] N/S,dddmm.mmmm[mm] E/W310      NS=a[1][-1]311      a[1]=a[1][:-1]312      EW=a[2][-1]313      a[2]=a[2][:-1]314      long=float(a[1])315      x=int(long/100)316      y=((long/100)-x)*10/6317      long=x+y318      ret_Arg['long']=long319      ret_Arg['NS']=NS320      lat=float(a[2])321      x=int(lat/100)322      y=((lat/100)-x)*10/6323      lat=x+y324      ret_Arg['lat']=lat325      ret_Arg['EW']=EW326      ret_Arg['hdop']=float(a[3])327      ret_Arg['altitude']=float(a[4])328      ret_Arg['fix']=a[5]+"D positioning"329      ret_Arg['cog']=float(a[6])330      ret_Arg['spkm']=float(a[7])331      ret_Arg['spkn']=float(a[8])332      date=a[9]333      ret_Arg['date']="20"+date[4:][0:2]+'/'+date[2:4]+'/'+date[0:2]334      ret_Arg['nsat']=float(a[10])335      ret_Arg['text']=result.split(': ')[1].split('\n')[0]336  return _answer(echo, ret, ret_Arg['text'], ret_Arg)337338def gnss_enable_nmea():339  print(cellular_tx('AT+QGPSCFG="nmeasrc",1', 500, False, True).replace('\r', '').strip())340341def gnss_disable_nmea():342  print(cellular_tx('AT+QGPSCFG="nmeasrc",0', 500, False, True).replace('\r', '').strip())343344def gnss_get_nmea(sentence="GGA"):345  """gets an NMEA sentence.346  Valid sentences are GGA,RMC,GSV,GSA,VTG,GNS347  If the sentence is GGA, the code tries to extract data348  and returns it into an object.349  """350  a=cellular_tx('AT+QGPSGNMEA="'+sentence+'"', 500, False, True)351  b=a.split("\n")352  for x in b:353    if(x.startswith('+QGPSGNMEA: $GPGGA')):354      c=x[12:]355      c=c.split(',')356      result={}357      time=c[1].split('.')358      time=time[0]359      result['tof']=time[0:2]+':'+time[2:4]+':'+time[4:]+' UTC'360      valid=c[6]361      if(valid==0):362        print("  Fix is not valid! Aborting.")363        result['valid']=False364        return result365      result['valid']=True366      SVs=c[7]367      result['SVs']=float(SVs)368      OrthoHeight=c[9]+' '+c[10]369      result['orthoheight']=float(c[9])370      long=float(c[2])371      NS=c[3]372      x=int(long/100)373      y=((long/100)-x)*10/6374      long=x+y375      result['long']=long376      result['NS']=NS377      lat=float(c[4])378      EW=c[5]379      x=int(lat/100)380      y=((lat/100)-x)*10/6381      lat=x+y382      result['lat']=lat383      result['EW']=EW384      return result385386def bg96_PI(echo=False, ret=True):387  """Gets the full Product Information.388  Equivalent to the next three commands plus bg96_IMEI."""389  result=cellular_tx('ATI', 300, False, True).replace('\r', '').strip().split('\n')390  # Since the IMEI is part of the product info, no reason not to get it together.391  IMEI=bg96_IMEI(False, True)392  echo_Arg="Manufacturer: "+result[1]+"\nProduct: "+result[2]+"\n"+result[3]+"\nIMEI: "+IMEI393  a={}394  a['manufacturer']=result[1]395  a['product']=result[2]396  a['revision']=result[3].split(': ')[1]397  a['IMEI']=IMEI398  return _answer(echo, ret, echo_Arg, a)399400def bg96_Manufacturer(echo=False, ret=True):401  """Gets the Manufacturer's Name'"""402  result=cellular_tx('AT+GMI', 300, False, True).replace('\r', '').strip().split('\n')403  return _answer(echo, ret, "Manufacturer: "+result[1], result[1])404405def bg96_Product(echo=False, ret=True):406  """Gets the Product Name"""407  result=cellular_tx('AT+GMM', 300, False, True).replace('\r', '').strip().split('\n')408  return _answer(echo, ret, "Product: "+result[1], result[1])409410def bg96_Revision(echo=False, ret=True):411  """Gets the Software Revision"""412  result=cellular_tx('AT+GMR', 300, False, True).replace('\r', '').strip().split('\n')413  return _answer(echo, ret, "Revision: "+result[1], result[1])414415def bg96_IMEI(echo=False, ret=True):416  """Gets the Device's IMEI'"""417  result=cellular_tx('AT+GSN', 300, False, True).replace('\r', '').strip().split('\n')418  return _answer(echo, ret, "IMEI: "+result[1], result[1])419420def bg96_IMSI(echo=False, ret=True):421  """Query IMSI number of (U)SIM"""422  result=cellular_tx('AT+CIMI', 300, False, True).replace('\r', '').strip().split('\n')423  return _answer(echo, ret, "IMSI: "+result[1], result[1])424425def bg96_ICCID(echo=False, ret=True):426  """Gets the ICCID of the (U)SIM card'"""427  result=cellular_tx('AT+QCCID', 300, False, True).replace('\r', '').strip().split('\n')428  return _answer(echo, ret, "CCID: "+result[1], result[1])429430_insertStatus=[]431_insertStatus.append('(U)SIM card is removed.')432_insertStatus.append('(U)SIM card is inserted.')433_insertStatus.append('(U)SIM card status unknown, before (U)SIM initialization.')434435def bg96_SIM_Insertion(echo=False, ret=True):436  """Query (U)SIM card insertion status."""437  result=cellular_tx('AT+QSIMSTAT?', 300, False, True).replace('\r', '').strip()438  if(result.find('\n+QSIMSTAT: ')>-1):439    #AT+QSIMSTAT?\n+QSIMSTAT: 1,0440    a=result.split('\n')[1].split(': ')[1].split(',')441    if(a[0]=='0'):442      echo_Arg="(U)SIM card insertion status report dis"443    else:444      echo_Arg="(U)SIM card insertion status report en"445    echo_Arg+="abled.\n"+_insertStatus[int(a[1])]446    ret_Arg={}447    ret_Arg['enabled']=(a[0]=='1')448    ret_Arg['statusCode']=int(a[1])449    ret_Arg['status']=_insertStatus[int(a[1])]450  else:451    echo_Arg=result452    ret_Arg=result453  return _answer(echo, ret, echo_Arg, ret_Arg)454455def bg96_FactoryDefault():456  """Resets the device to Factory Default"""457  result=cellular_tx('AT&F', 300, False, True).replace('\r', '').strip()458  print(result)459460def bg96_Config():461  """Gets the Current Configuration"""462  result=cellular_tx('AT&V', 300, False, True).replace('\r', '').strip()463  result=result.replace('\n', '\nAT')464  result=result[:-7]465  print(result)466467def bg96_Save_User_Profile():468  """Saves the Current Configuration to the USer Profile"""469  result=cellular_tx('AT&W', 300, False, True).replace('\r', '').strip()470  print(result)471472def bg96_Load_User_Profile():473  """Loads the User Profile Configuration"""474  result=cellular_tx('ATZ', 300, False, True).replace('\r', '').strip()475  print(result)476477def bg96_Set_Result_Code(code=0):478  """Sets the Result Code Display to ON or OFF"""479  if(code<0) or (code>1):480    print("Use 0 for yes or")481    print("1 for no")482    return483  result=cellular_tx('ATQ'+str(code), 300, False, True).replace('\r', '').strip()484  print(result)485486def bg96_Result_code_On():487  """Sets the Result Code Display to ON"""488  result=cellular_tx('ATQ0', 300, False, True).replace('\r', '').strip()489  print(result)490491def bg96_Result_code_Off():492  """Sets the Result Code Display to OFF"""493  result=cellular_tx('ATQ1', 300, False, True).replace('\r', '').strip()494  print(result)495496def bg96_Set_Result_Code_Verbosity(code=0):497  """Sets the Result Code Verbosity"""498  if(code<0) or (code>1):499    print("Use 0 for non-verbose or")500    print("1 for verbose")501    return502  result=cellular_tx('ATV'+str(code), 300, False, True).replace('\r', '').strip()503  print(result)504505def bg96_Set_Command_Echo(code=0):506  """Sets the Command Echo to ON or OFF"""507  if(code<0) or (code>1):508    print("Use 0 for echo off or")509    print("1 for echo on")510    return511  result=cellular_tx('ATE'+str(code), 300, False, True).replace('\r', '').strip()512  print(result)513514def bg96_Power_Down(code=1):515  """Powers down the device"""516  if(code<0) or (code>1):517    print("Use 0 for immediate power down or")518    print("1 for normal power down")519    return520  result=cellular_tx('AT+QPOWD'+str(code), 300, False, True).replace('\r', '').strip()521  print(result)522523def bg96_Read_Clock(echo=False, ret=True):524  """Gets the time from the RTC525  Returns a dict with two key/value pairs526  date: yy/mm/dd527  time: hh:mm:ss528  """529  result=cellular_tx('AT+CCLK?', 300, False, True).replace('\r', '').strip()530  if(result.find('\n+CCLK: ')>-1):531    #AT+CCLK?\n+CCLK: "80/01/06,01:24:14"532    a=result.split('"')[1]533    echo_Arg=a534    a=a.split(',')535    ret_Arg={}536    ret_Arg['date']=a[0]537    ret_Arg['time']=a[1]538  else:539    echo_Arg=result540    ret_Arg=result541  return _answer(echo, ret, echo_Arg, ret_Arg)542543def bg96_Battery(echo=False, ret=True):544  """Gets the battery charging status545  Returns a dict with four key/value pairs546  code: [012]547  volt: <float>548  charging: True/False549  percent: <float>550  """551  result=cellular_tx('AT+CBC', 300, False, True).replace('\r', '').strip()552  if(result.startswith('AT+CBC\n+CBC: ')):553    a=result.split(': ')[1].split('\n')[0].split(',')554    if(a[0]=='0'):555      echo_Arg="Not charging... ["+a[1]+"% "+str(float(a[2])/1000)+"V]"556    if(a[0]=='1'):557      echo_Arg="Charging: "+a[1]+"% "+str(float(a[2])/1000)+"V"558    if(a[0]=='2'):559      echo_Arg="Done charging: "+a[1]+"% "+str(float(a[2])/1000)+"V"560    ret_Arg={}561    ret_Arg['code']=int(a[0])562    ret_Arg['charging']=(a[0]=='1')563    ret_Arg['percent']=float(a[1])564    ret_Arg['volt']=float(a[2])/1000565  else:566    echo_Arg=result567    ret_Arg={}568  return _answer(echo, ret, echo_Arg, ret_Arg)569570def bg96_Temp(echo=False, ret=True):571  """Gets the temperature for PMIC, XO and PA"""572  result=cellular_tx('AT+QTEMP', 300, False, True).replace('\r', '').strip()573  if(result.startswith('AT+QTEMP\n+QTEMP: ')):574    a=result.split(': ')[1].split('\n')[0].split(',')575    ret_Arg={}576    ret_Arg['PMIC']=float(a[0])577    ret_Arg['XO']=float(a[1])578    ret_Arg['PA']=float(a[2])579    echo_Arg="PMIC: "+a[0]+" C\nXO:   "+a[1]+" C\nPA:   "+a[2]+" C"580  else:581    echo_Arg="Unknown result code:\n  "+result582    ret_Arg={}583  return _answer(echo, ret, echo_Arg, ret_Arg)584585_br9600=9600586_br19200=19200587_br38400=38400588_br57600=57600589_br115200=115200590_br230400=230400591_br460800=460800592_br921600=921600593594def bg96_Set_Baud_Rate(rate=115200, echo=False, ret=True):595  result=cellular_tx('AT+IPR='+str(rate), 300, False, True).replace('\r', '').strip()596  return _answer(echo, ret, result, result)597598_cpasStatus=[]599_cpasStatus.append('Ready')600_cpasStatus.append('Ringing')601_cpasStatus.append('Call in progress or call hold')602603def bg96_Activity_Status(echo=False, ret=True):604  result=cellular_tx('AT+CPAS', 300, False, True).replace('\r', '').strip().split('\n')[1]605  if(result.startswith('+CPAS: ')):606    a=int(result.split(': ')[1])607    ret_Arg={}608    ret_Arg['code']=a609    ret_Arg['text']=_cpasStatus[a]610    echo_Arg=_cpasStatus[a]+" ["+str(a)+"]"611  else:612    ret_Arg=result613    echo_Arg=result
...CommandRemind.py
Source:CommandRemind.py  
1import SQLiteInterface as SQI2import re3import datetime4logtag = 'CommandRemind: '5async def entry(cmdArgs, message):6    if len(cmdArgs) < 2:7        await message.channel.send('Invalid format, give at least [hh:mm time to wait] [reminder text]')8        return 9    valid_ret = validate_command(cmdArgs)10    if valid_ret[0]:11        pass12    else:13        print(valid_ret[1])14    # date [date] [clock time]15    # eg >remind date 09/15/2021 15:30 smack Sam16    # the reminder will go out on 9/15/2021 at 15:3017    # time [clock time]18    # eg >remind 15:30 smack Sam19    # the next time 15:30 rolls around the reminder will go out20    # [time in hr:min]21    # eg >remind 4:30 smack Sam22    # Timer, runs for the amount of time given23def validate_command(args):24    cmd_type = args[0]25    cmd_args = args[1:]26    date_err = '''Invalid format. Use "remind date [mm/dd/yyyy] [hh:mm] [reminder text]"'''27    time_err = '''Invalid format. Use "remind time [hh:mm] [reminder text]"'''28    if cmd_type == 'date':29        if len(cmd_args) < 3:30            return [False, date_err]31        date_arg_str = cmd_args[0]32        time_arg_str = cmd_args[1]33        msg_arg = cmd_args[2]34        date_arg = split_date_arg(date_arg_str)35        if date_arg[3]:36            return [False, date_err]37        if not is_valid_date(date_arg):38            return [False, date_err]39        time_arg = split_time_arg(time_arg_str)40        if time_arg[2]:41            return [False, date_err]42        if not is_valid_time(time_arg):43            return [False, date_err]44        # Set the reminder45        return [True, create_reminder(date_arg[:-1] + time_arg[:-1], msg_arg)]46    elif cmd_type == 'time':47        if len(cmd_args) < 2:48            return [False, time_err]49        time_arg_str = cmd_args[0]50        msg_arg = cmd_args[1]51        time_arg = split_time_arg(time_arg_str)52        if time_arg[2]:53            return [False, time_err]54        if not is_valid_time(time_arg):55            return [False, time_err]56        ct = datetime.datetime.now()57        current_datetime = [ct.month, ct.day, ct.year, ct.hour, ct.minute]58        if time_is_after(time_arg[:-1], [ct.hour, ct.minute]):59            return [True, create_reminder(current_datetime[0:3] + time_arg[:-1], msg_arg)]60        else:61            new_date = add_date_args(current_datetime[0:3], [0, 1, 0])62            return [True, create_reminder(new_date + time_arg[:-1], msg_arg)]63    else:  # No command type, just set a timer for the given duration64        pass65# Takes datetime styled argument - [month, day, year, hour, minute] and the msg_arg66def create_reminder(datetime_arg, msg_arg):67    pass68# Adds date_args together, returns the total date_arg69# The second date arg is added literally, and is not interpreted as an actual date70def add_date_args(a, b):71    ret_arg = a72    ret_arg[0] += b[0]73    ret_arg[1] += b[1]74    ret_arg[2] += b[2]75    # Correct days/months76    valid = False77    while not valid:78        if ret_arg[0] in [1, 3, 5, 7, 8, 10, 12]:79            if ret_arg[1] > 31:80                ret_arg[1] -= 3181                ret_arg[0] += 182            else:83                valid = True84        elif ret_arg[0] in [4, 6, 9, 11]:85            if ret_arg[1] > 30:86                ret_arg[1] -= 3087                ret_arg[0] += 188            else:89                valid = True90        else:91            if is_leap_year(ret_arg[2]):92                if ret_arg[1] > 29:93                    ret_arg[1] -= 2994                    ret_arg[0] += 195                else:96                    valid = True97            else:98                if ret_arg[1] > 28:99                    ret_arg[1] -= 28100                    ret_arg[0] += 1101                else:102                    valid = True103    # Correct months/years104    while ret_arg[0] > 12:105        ret_arg[2] += 1106        ret_arg[0] -= 12107    while ret_arg[0] < 1:108        ret_arg[2] -= 1109        ret_arg[0] += 12110    return ret_arg111# Takes 2 time_args and returns if the first is after the second112def time_is_after(a, b):113    if a[0] == b[0]:114        return a[1] > b[1]115    return a[0] > b[0]116# Splits the given time string into 2 parts, all ints117# Returns [h, m, err] - h, m are 0 when err == True118def split_time_arg(arg):119    split_arg = re.split(':', arg)120    if len(split_arg) != 2:121        return [0, 0, True]122    else:123        return [int(split_arg[0]), int(split_arg[1]), False]124# Splits the given date string into 3 parts, all ints125# Returns [m, d, y, err] - m, d, and y are 0 when err == True126def split_date_arg(arg):127    split_arg = re.split('/|-', arg)128    if len(split_arg) != 3:129        return [0, 0, 0, True]130    else:131        return [int(split_arg[0]), int(split_arg[1]), int(split_arg[2]), False]132# Check that the given time, in int format, is a valid time133def is_valid_time(v):134    h = v[0]135    m = v[0]136    if h > 23 or h < 0:137        return False138    if m > 59 or m < 0:139        return False140    return True141# Check that the given date, in int format, is a valid date142def is_valid_date(v):143    m = v[0]144    d = v[1]145    y = v[2]146    if m > 12 or m < 1:147        return False148    if d < 1:149        return False150    if m in [1, 3, 5, 7, 8, 10, 12]:151        return d <= 31152    elif m in [4, 6, 9, 11]:153        return d <= 30154    else:155        if is_leap_year(y):156            return d <= 29157        else:158            return d <= 28159def is_leap_year(y):160    if y % 2000:161        return False...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
