code: def _get_bti_info(
      pdf_fname,
      config_fname,
      head_shape_fname,
      rotation_x,
      translation,
      convert,
      ecg_ch,
      eog_ch,
      rename_channels=True,
      sort_by_ch_name=True,
  ):
      """Read BTI info.
  
      Note. This helper supports partial construction of infos when `pdf_fname`
      is None. Some datasets, such as the HCP, are shipped as a large collection
      of zipped files where it can be more efficient to only read the needed
      information. In such a situation, some information can neither be accessed
      directly nor guessed based on the `config`.
  
      These fields will thus be set to None:
          - 'lowpass'
          - 'highpass'
          - 'sfreq'
          - 'meas_date'
  
      """
      if pdf_fname is None:
          logger.info(
              "No pdf_fname passed, trying to construct partial info "
              "from config"
          )
      if pdf_fname is not None and not isinstance(pdf_fname, BytesIO):
          if not op.isabs(pdf_fname):
              pdf_fname = op.abspath(pdf_fname)
  
      if not isinstance(config_fname, BytesIO):
          if not op.isabs(config_fname):
              config_tries = [
                  op.abspath(config_fname),
                  op.abspath(
                      op.join(op.dirname(pdf_fname), config_fname)
                  ),
              ]
              for config_try in config_tries:
                  if op.isfile(config_try):
                      config_fname = config_try
                      break
          if not op.isfile(config_fname):
              raise ValueError(
                  "Could not find the config file %s. Please check"
                  " whether you are in the right directory "
                  "or pass the full name" % config_fname
              )
  
      if head_shape_fname is not None and not isinstance(
          head_shape_fname, BytesIO
      ):
          orig_name = head_shape_fname
          if not op.isfile(head_shape_fname):
              head_shape_fname = op.join(
                  op.dirname(pdf_fname), head_shape_fname
              )
  
          if not op.isfile(head_shape_fname):
              raise ValueError(
                  'Could not find the head_shape file "%s". '
                  "You should check whether you are in the "
                  "right directory, pass the full file name, "
                  "or pass head_shape_fname=None." % orig_name
              )
  
      logger.info("Reading 4D PDF file %s..." % pdf_fname)
      bti_info = _read_bti_header(
          pdf_fname, config_fname, sort_by_ch_name=sort_by_ch_name
      )
      extras = dict(
          pdf_fname=pdf_fname,
          head_shape_fname=head_shape_fname,
          config_fname=config_fname,
      )
      for key, val in extras.items():
          bti_info[key] = None if isinstance(val, BytesIO) else val
  
      dev_ctf_t = Transform(
          "ctf_meg",
          "ctf_head",
          _correct_trans(bti_info["bti_transform"][0]),
      )
  
      _check_nan_dev_head_t(dev_ctf_t)
      # for old backward compatibility and external processing
      rotation_x = 0.0 if rotation_x is None else rotation_x
      bti_dev_t = (
          _get_bti_dev_t(rotation_x, translation) if convert else None
      )
      bti_dev_t = Transform("ctf_meg", "meg", bti_dev_t)
  
      use_hpi = False  # hard coded, but marked as later option.
      logger.info("Creating Neuromag info structure ...")
      if "sample_period" in bti_info.keys():
          sfreq = 1.0 / bti_info["sample_period"]
      else:
          sfreq = None
  
      if pdf_fname is not None:
          info = _empty_info(sfreq)
          date = bti_info["processes"][0]["timestamp"]
          info["meas_date"] = _stamp_to_dt((date, 0))
      else:  # these cannot be guessed from config, see docstring
          info = _empty_info(1.0)
          info["sfreq"] = None
          info["lowpass"] = None
          info["highpass"] = None
          info["meas_date"] = None
          bti_info["processes"] = list()
  
      # browse processing info for filter specs.
      hp, lp = info["highpass"], info["lowpass"]
      for proc in bti_info["processes"]:
          if "filt" in proc["process_type"]:
              for step in proc["processing_steps"]:
                  if "high_freq" in step:
                      hp, lp = step["high_freq"], step["low_freq"]
                  elif "hp" in step["process_type"]:
                      hp = step["freq"]
                  elif "lp" in step["process_type"]:
                      lp = step["freq"]
  
      info["highpass"] = hp
      info["lowpass"] = lp
      chs = []
  
      # Note that 'name' and 'chan_label' are not the same.
      # We want the configured label if out IO parsed it
      # except for the MEG channels for which we keep the config name
      bti_ch_names = list()
      for ch in bti_info["chs"]:
          # we have always relied on 'A' as indicator of MEG data channels.
          ch_name = ch["name"]
          if not ch_name.startswith("A"):
              ch_name = ch.get("chan_label", ch_name)
          bti_ch_names.append(ch_name)
  
      neuromag_ch_names = _rename_channels(
          bti_ch_names, ecg_ch=ecg_ch, eog_ch=eog_ch
      )
      ch_mapping = zip(bti_ch_names, neuromag_ch_names)
  
      logger.info("... Setting channel info structure.")
      for idx, (chan_4d, chan_neuromag) in enumerate(ch_mapping):
          chan_info = _instantiate_default_info_chs()
          chan_info["ch_name"] = (
              chan_neuromag if rename_channels else chan_4d
          )
          chan_info["logno"] = idx + BTI.FIFF_LOGNO
          chan_info["scanno"] = idx + 1
          chan_info["cal"] = float(bti_info["chs"][idx]["scale"])
  
          if any(chan_4d.startswith(k) for k in ("A", "M", "G")):
              loc = bti_info["chs"][idx]["loc"]
              if loc is not None:
                  if convert:
                      if idx == 0:
                          logger.info(
                              "... putting coil transforms in Neuromag "
                              "coordinates"
                          )
                      t = _loc_to_coil_trans(
                          bti_info["chs"][idx]["loc"]
                      )
                      t = _convert_coil_trans(t, dev_ctf_t, bti_dev_t)
                      loc = _coil_trans_to_loc(t)
              chan_info["loc"] = loc
  
          # BTI sensors are natively stored in 4D head coords we believe
          meg_frame = (
              FIFF.FIFFV_COORD_DEVICE
              if convert
              else FIFF.FIFFV_MNE_COORD_4D_HEAD
          )
          eeg_frame = (
              FIFF.FIFFV_COORD_HEAD
              if convert
              else FIFF.FIFFV_MNE_COORD_4D_HEAD
          )
          if chan_4d.startswith("A"):
              chan_info["kind"] = FIFF.FIFFV_MEG_CH
              chan_info["coil_type"] = FIFF.FIFFV_COIL_MAGNES_MAG
              chan_info["coord_frame"] = meg_frame
              chan_info["unit"] = FIFF.FIFF_UNIT_T
  
          elif chan_4d.startswith("M"):
              chan_info["kind"] = FIFF.FIFFV_REF_MEG_CH
              chan_info["coil_type"] = FIFF.FIFFV_COIL_MAGNES_REF_MAG
              chan_info["coord_frame"] = meg_frame
              chan_info["unit"] = FIFF.FIFF_UNIT_T
  
          elif chan_4d.startswith("G"):
              chan_info["kind"] = FIFF.FIFFV_REF_MEG_CH
              chan_info["coord_frame"] = meg_frame
              chan_info["unit"] = FIFF.FIFF_UNIT_T_M
              if chan_4d in ("GxxA", "GyyA"):
                  chan_info[
                      "coil_type"
                  ] = FIFF.FIFFV_COIL_MAGNES_REF_GRAD
              elif chan_4d in ("GyxA", "GzxA", "GzyA"):
                  chan_info[
                      "coil_type"
                  ] = FIFF.FIFFV_COIL_MAGNES_OFFDIAG_REF_GRAD
  
          elif chan_4d.startswith("EEG") or _eeg_like(chan_4d):
              chan_info["kind"] = FIFF.FIFFV_EEG_CH
              chan_info["coil_type"] = FIFF.FIFFV_COIL_EEG
              chan_info["coord_frame"] = eeg_frame
              chan_info["unit"] = FIFF.FIFF_UNIT_V
              # TODO: We should use 'electrodes' to fill this in, and make sure
              # we turn them into dig as well
              chan_info["loc"][:3] = np.nan
  
          elif chan_4d == "RESPONSE":
              chan_info["kind"] = FIFF.FIFFV_STIM_CH
          elif chan_4d == "TRIGGER":
              chan_info["kind"] = FIFF.FIFFV_STIM_CH
          elif (
              chan_4d.startswith("EOG")
              or chan_4d[:4] in ("HEOG", "VEOG")
              or chan_4d in eog_ch
          ):
              chan_info["kind"] = FIFF.FIFFV_EOG_CH
          elif chan_4d.startswith("EMG"):
              chan_info["kind"] = FIFF.FIFFV_EMG_CH
          elif chan_4d == ecg_ch or chan_4d.startswith("ECG"):
              chan_info["kind"] = FIFF.FIFFV_ECG_CH
          # Our default is now misc, but if we ever change that,
          # we'll need this:
          # elif chan_4d.startswith('X') or chan_4d == 'UACurrent':
          #     chan_info['kind'] = FIFF.FIFFV_MISC_CH
  
          chs.append(chan_info)
  
      info["chs"] = chs
  
      # ### Dig stuff
      info = _make_bti_digitization(
          info, head_shape_fname, convert, use_hpi, bti_dev_t, dev_ctf_t
      )
  
      logger.info(
          "Currently direct inclusion of 4D weight tables is not supported."
          " For critical use cases please take into account the MNE command"
          ' "mne_create_comp_data" to include weights as printed out by '
          'the 4D "print_table" routine.'
      )
  
      # check that the info is complete
      info._unlocked = False
      info._update_redundant()
      info._check_consistency()
      return info, bti_info
  
imports: import functools
  import os.path
  from io import BytesIO
  from itertools import count
  import numpy
  from ..._fiff._digitization import _make_bti_dig_points
  from ..._fiff.constants import FIFF
  from ..._fiff.meas_info import _empty_info
  from ..._fiff.tag import _coil_trans_to_loc, _loc_to_coil_trans
  from ..._fiff.utils import _mult_cal_one, read_str
  from ...transforms import Transform, combine_transforms, invert_transform
  from ...utils import _stamp_to_dt, _validate_type, logger, path_like, verbose
  from ..base import BaseRaw
  from .constants import BTI
  from .read import read_char, read_dev_header, read_double, read_double_matrix, read_float, read_float_matrix, read_int16, read_int16_matrix, read_int32, read_int64, read_transform, read_uint16, read_uint32
label_desc: Use image node_id 24 for calling a global function with example usage: _get_bti_info(pdf_fname, config_fname, head_shape_fname, rotation_x, translation, convert, ecg_ch, eog_ch, rename_channels, sort_by_ch_name) and returns: info,  bti_info