code: def _get_artemis123_info(fname, pos_fname=None):
      """Generate info struct from artemis123 header file."""
      fname = op.splitext(fname)[0]
      header = fname + ".txt"
  
      logger.info("Reading header...")
  
      # key names for artemis channel info...
      chan_keys = [
          "name",
          "scaling",
          "FLL_Gain",
          "FLL_Mode",
          "FLL_HighPass",
          "FLL_AutoReset",
          "FLL_ResetLock",
      ]
  
      header_info = dict()
      header_info["filter_hist"] = []
      header_info["comments"] = ""
      header_info["channels"] = []
  
      with open(header) as fid:
          # section flag
          # 0 - None
          # 1 - main header
          # 2 - channel header
          # 3 - comments
          # 4 - length
          # 5 - filtering History
          sectionFlag = 0
          for line in fid:
              # skip emptylines or header line for channel info
              if (not line.strip()) or (
                  sectionFlag == 2 and line.startswith("DAQ Map")
              ):
                  continue
  
              # set sectionFlag
              if line.startswith("<end"):
                  sectionFlag = 0
              elif line.startswith("<start main header>"):
                  sectionFlag = 1
              elif line.startswith("<start per channel header>"):
                  sectionFlag = 2
              elif line.startswith("<start comments>"):
                  sectionFlag = 3
              elif line.startswith("<start length>"):
                  sectionFlag = 4
              elif line.startswith("<start filtering history>"):
                  sectionFlag = 5
              else:
                  # parse header info lines
                  # part of main header - lines are name value pairs
                  if sectionFlag == 1:
                      values = line.strip().split("\t")
                      if len(values) == 1:
                          values.append("")
                      header_info[values[0]] = values[1]
                  # part of channel header - lines are Channel Info
                  elif sectionFlag == 2:
                      values = line.strip().split("\t")
                      if len(values) != 7:
                          raise OSError(
                              "Error parsing line \n\t:%s\n" % line
                              + "from file %s" % header
                          )
                      tmp = dict()
                      for k, v in zip(chan_keys, values):
                          tmp[k] = v
                      header_info["channels"].append(tmp)
                  elif sectionFlag == 3:
                      header_info["comments"] = "%s%s" % (
                          header_info["comments"],
                          line.strip(),
                      )
                  elif sectionFlag == 4:
                      header_info["num_samples"] = int(line.strip())
                  elif sectionFlag == 5:
                      header_info["filter_hist"].append(line.strip())
  
      for k in [
          "Temporal Filter Active?",
          "Decimation Active?",
          "Spatial Filter Active?",
      ]:
          if header_info[k] != "FALSE":
              warn("%s - set to but is not supported" % k)
      if header_info["filter_hist"]:
          warn(
              "Non-Empty Filter history found, BUT is not supported" % k
          )
  
      # build mne info struct
      info = _empty_info(float(header_info["DAQ Sample Rate"]))
  
      # Attempt to get time/date from fname
      # Artemis123 files saved from the scanner observe the following
      # naming convention 'Artemis_Data_YYYY-MM-DD-HHh-MMm_[chosen by user].bin'
      try:
          date = datetime.datetime.strptime(
              op.basename(fname).split("_")[2], "%Y-%m-%d-%Hh-%Mm"
          )
          meas_date = (calendar.timegm(date.utctimetuple()), 0)
      except Exception:
          meas_date = None
  
      # build subject info must be an integer (as per FIFF)
      try:
          subject_info = {"id": int(header_info["Subject ID"])}
      except ValueError:
          subject_info = {"id": 0}
  
      # build description
      desc = ""
      for k in ["Purpose", "Notes"]:
          desc += f"{k} : {header_info[k]}\n"
      desc += "Comments : {}".format(header_info["comments"])
  
      info.update(
          {
              "meas_date": meas_date,
              "description": desc,
              "subject_info": subject_info,
              "proj_name": header_info["Project Name"],
          }
      )
  
      # Channel Names by type
      ref_mag_names = [
          "REF_001",
          "REF_002",
          "REF_003",
          "REF_004",
          "REF_005",
          "REF_006",
      ]
  
      ref_grad_names = [
          "REF_007",
          "REF_008",
          "REF_009",
          "REF_010",
          "REF_011",
          "REF_012",
      ]
  
      # load mne loc dictionary
      loc_dict = _load_mne_locs()
      info["chs"] = []
      bads = []
  
      for i, chan in enumerate(header_info["channels"]):
          # build chs struct
          t = {
              "cal": float(chan["scaling"]),
              "ch_name": chan["name"],
              "logno": i + 1,
              "scanno": i + 1,
              "range": 1.0,
              "unit_mul": FIFF.FIFF_UNITM_NONE,
              "coord_frame": FIFF.FIFFV_COORD_DEVICE,
          }
          # REF_018 has a zero cal which can cause problems. Let's set it to
          # a value of another ref channel to make writers/readers happy.
          if t["cal"] == 0:
              t["cal"] = 4.716e-10
              bads.append(t["ch_name"])
          t["loc"] = loc_dict.get(chan["name"], np.zeros(12))
  
          if chan["name"].startswith("MEG"):
              t["coil_type"] = FIFF.FIFFV_COIL_ARTEMIS123_GRAD
              t["kind"] = FIFF.FIFFV_MEG_CH
              # While gradiometer units are T/m, the meg sensors referred to as
              # gradiometers report the field difference between 2 pick-up coils.
              # Therefore the units of the measurements should be T
              # *AND* the baseline (difference between pickup coils)
              # should not be used in leadfield / forwardfield computations.
              t["unit"] = FIFF.FIFF_UNIT_T
              t["unit_mul"] = FIFF.FIFF_UNITM_F
  
          # 3 axis reference magnetometers
          elif chan["name"] in ref_mag_names:
              t["coil_type"] = FIFF.FIFFV_COIL_ARTEMIS123_REF_MAG
              t["kind"] = FIFF.FIFFV_REF_MEG_CH
              t["unit"] = FIFF.FIFF_UNIT_T
              t["unit_mul"] = FIFF.FIFF_UNITM_F
  
          # reference gradiometers
          elif chan["name"] in ref_grad_names:
              t["coil_type"] = FIFF.FIFFV_COIL_ARTEMIS123_REF_GRAD
              t["kind"] = FIFF.FIFFV_REF_MEG_CH
              # While gradiometer units are T/m, the meg sensors referred to as
              # gradiometers report the field difference between 2 pick-up coils.
              # Therefore the units of the measurements should be T
              # *AND* the baseline (difference between pickup coils)
              # should not be used in leadfield / forwardfield computations.
              t["unit"] = FIFF.FIFF_UNIT_T
              t["unit_mul"] = FIFF.FIFF_UNITM_F
  
          # other reference channels are unplugged and should be ignored.
          elif chan["name"].startswith("REF"):
              t["coil_type"] = FIFF.FIFFV_COIL_NONE
              t["kind"] = FIFF.FIFFV_MISC_CH
              t["unit"] = FIFF.FIFF_UNIT_V
              bads.append(t["ch_name"])
  
          elif chan["name"].startswith(("AUX", "TRG", "MIO")):
              t["coil_type"] = FIFF.FIFFV_COIL_NONE
              t["unit"] = FIFF.FIFF_UNIT_V
              if chan["name"].startswith("TRG"):
                  t["kind"] = FIFF.FIFFV_STIM_CH
              else:
                  t["kind"] = FIFF.FIFFV_MISC_CH
          else:
              raise ValueError(
                  "Channel does not match expected"
                  + ' channel Types:"%s"' % chan["name"]
              )
  
          # incorporate multiplier (unit_mul) into calibration
          t["cal"] *= 10 ** t["unit_mul"]
          t["unit_mul"] = FIFF.FIFF_UNITM_NONE
  
          # append this channel to the info
          info["chs"].append(t)
          if chan["FLL_ResetLock"] == "TRUE":
              bads.append(t["ch_name"])
  
      # HPI information
      # print header_info.keys()
      hpi_sub = dict()
      # Don't know what event_channel is don't think we have it HPIs are either
      # always on or always off.
      # hpi_sub['event_channel'] = ???
      hpi_sub["hpi_coils"] = [dict(), dict(), dict(), dict()]
      hpi_coils = [dict(), dict(), dict(), dict()]
      drive_channels = ["MIO_001", "MIO_003", "MIO_009", "MIO_011"]
      key_base = "Head Tracking %s %d"
  
      # set default HPI frequencies
      if info["sfreq"] == 1000:
          default_freqs = [140, 150, 160, 40]
      else:
          default_freqs = [700, 750, 800, 40]
  
      for i in range(4):
          # build coil structure
          hpi_coils[i]["number"] = i + 1
          hpi_coils[i]["drive_chan"] = drive_channels[i]
          this_freq = header_info.pop(
              key_base % ("Frequency", i + 1), default_freqs[i]
          )
          hpi_coils[i]["coil_freq"] = this_freq
  
          # check if coil is on
          if header_info[key_base % ("Channel", i + 1)] == "OFF":
              hpi_sub["hpi_coils"][i]["event_bits"] = [0]
          else:
              hpi_sub["hpi_coils"][i]["event_bits"] = [256]
  
      info["hpi_subsystem"] = hpi_sub
      info["hpi_meas"] = [{"hpi_coils": hpi_coils}]
      # read in digitized points if supplied
      if pos_fname is not None:
          info["dig"] = _read_pos(pos_fname)
      else:
          info["dig"] = []
  
      info._unlocked = False
      info._update_redundant()
      # reduce info['bads'] to unique set
      info["bads"] = list(set(bads))
      del bads
      return info, header_info
  
file_path: mne-python/mne/io/artemis123/artemis123.py
imports: import calendar
  import datetime
  import os.path
  import numpy
  from scipy.spatial.distance import cdist
  from ..._fiff._digitization import DigPoint, _make_dig_points
  from ..._fiff.constants import FIFF
  from ..._fiff.meas_info import _empty_info
  from ..._fiff.utils import _read_segments_file
  from ...transforms import Transform, apply_trans, get_ras_to_neuromag_trans
  from ...utils import _check_fname, logger, verbose, warn
  from ..base import BaseRaw
  from .utils import _load_mne_locs, _read_pos
label_desc: Use image node_id 2 for calling a global function with example usage: _get_artemis123_info(fname, pos_fname) and returns: info,  header_info