Example #1
0
//******************************************************************************
/// \brief Handle bridge reset command
/// \return #mxt_rc
static int bridge_handle_reset(struct mxt_device *mxt,
                               struct bridge_context *bridge_ctx,
                               uint16_t address)
{
  int ret;
  char *response;
  const char * const PREFIX = "RST ";
  size_t response_len = 8;

  /* Allow for newline/null byte */
  response = calloc(response_len, sizeof(uint8_t));
  if (!response) {
    mxt_err(mxt->ctx, "Failed to allocate memory");
    ret = MXT_ERROR_NO_MEM;
    goto free;
  }

  strcpy(response, PREFIX);
  ret =  mxt_reset_chip(mxt, false);
  if (ret) {
    mxt_warn(mxt->ctx, "RST ERR");
    strcpy(response + strlen(PREFIX), "ERR\n");
    response_len = strlen(response);
  } else {
    mxt_info(mxt->ctx, "RST OK");
    strcpy(response + strlen(PREFIX), "OK\n");
    response_len = strlen(response);
  }

  ret = write(bridge_ctx->sockfd, response, response_len);
  if (ret < 0) {
    mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
    ret = mxt_errno_to_rc(errno);
    goto free;
  }

  ret = MXT_SUCCESS;

free:
  free(response);
  return ret;
}
Example #2
0
//******************************************************************************
/// \brief Main function for mxt-app
int main (int argc, char *argv[])
{
  int ret;
  int c;
  int msgs_timeout = MSG_CONTINUOUS;
  bool msgs_enabled = false;
  uint8_t backup_cmd = BACKUPNV_COMMAND;
  unsigned char self_test_cmd = SELF_TEST_ALL;
  uint16_t address = 0;
  uint16_t count = 0;
  struct mxt_conn_info *conn = NULL;
  uint16_t object_type = 0;
  uint16_t msg_filter_type = 0;
  uint8_t instance = 0;
  uint8_t verbose = 2;
  uint16_t t37_frames = 1;
  uint8_t t37_mode = DELTAS_MODE;
  bool format = false;
  uint16_t port = 4000;
  uint8_t t68_datatype = 1;
  unsigned char databuf;
  char strbuf2[BUF_SIZE];
  char strbuf[BUF_SIZE];
  strbuf[0] = '\0';
  strbuf2[0] = '\0';
  mxt_app_cmd cmd = CMD_NONE;

  while (1) {
    int option_index = 0;

    static struct option long_options[] = {
      {"backup",           optional_argument, 0, 0},
      {"bootloader-version", no_argument,     0, 0},
      {"bridge-client",    required_argument, 0, 'C'},
      {"calibrate",        no_argument,       0, 0},
      {"checksum",         required_argument, 0, 0},
      {"debug-dump",       required_argument, 0, 0},
      {"device",           required_argument, 0, 'd'},
      {"t68-file",         required_argument, 0, 0},
      {"t68-datatype",     required_argument, 0, 0},
      {"msg-filter",       required_argument, 0, 'F'},
      {"format",           no_argument,       0, 'f'},
      {"flash",            required_argument, 0, 0},
      {"firmware-version", required_argument, 0, 0},
      {"frames",           required_argument, 0, 0},
      {"help",             no_argument,       0, 'h'},
      {"info",             no_argument,       0, 'i'},
      {"instance",         required_argument, 0, 'I'},
      {"load",             required_argument, 0, 0},
      {"save",             required_argument, 0, 0},
      {"messages",         optional_argument, 0, 'M'},
      {"count",            required_argument, 0, 'n'},
      {"port",             required_argument, 0, 'p'},
      {"query",            no_argument,       0, 'q'},
      {"read",             no_argument,       0, 'R'},
      {"reset",            no_argument,       0, 0},
      {"reset-bootloader", no_argument,       0, 0},
      {"register",         required_argument, 0, 'r'},
      {"references",       no_argument,       0, 0},
      {"self-cap-tune-config", no_argument,       0, 0},
      {"self-cap-tune-nvram",  no_argument,       0, 0},
      {"self-cap-signals", no_argument,       0, 0},
      {"self-cap-deltas",  no_argument,       0, 0},
      {"self-cap-refs",    no_argument,       0, 0},
      {"bridge-server",    no_argument,       0, 'S'},
      {"test",             optional_argument, 0, 't'},
      {"type",             required_argument, 0, 'T'},
      {"verbose",          required_argument, 0, 'v'},
      {"version",          no_argument,       0, 0},
      {"write",            no_argument,       0, 'W'},
      {"zero",             no_argument,       0, 0},
      {0,                  0,                 0,  0 }
    };

    c = getopt_long(argc, argv,
                    "C:d:D:fF:ghiI:M::m:n:p:qRr:St::T:v:W",
                    long_options, &option_index);
    if (c == -1)
      break;

    switch (c) {
    case 0:
      if (!strcmp(long_options[option_index].name, "t68-file")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_SERIAL_DATA;
          strncpy(strbuf, optarg, sizeof(strbuf));
          strbuf[sizeof(strbuf) - 1] = '\0';
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "t68-datatype")) {
        t68_datatype = strtol(optarg, NULL, 0);
      } else if (!strcmp(long_options[option_index].name, "flash")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_FLASH;
          strncpy(strbuf, optarg, sizeof(strbuf));
          strbuf[sizeof(strbuf) - 1] = '\0';
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "backup")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_BACKUP;
          if (optarg) {
            ret = mxt_convert_hex(optarg, &databuf, &count, sizeof(databuf));
            if (ret || count == 0) {
              fprintf(stderr, "Hex convert error\n");
              ret = MXT_ERROR_BAD_INPUT;
            }
            backup_cmd = databuf;
          }
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "calibrate")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_CALIBRATE;
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "debug-dump")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_DEBUG_DUMP;
          strncpy(strbuf, optarg, sizeof(strbuf));
          strbuf[sizeof(strbuf) - 1] = '\0';
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "reset")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_RESET;
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "self-cap-tune-config")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_SELF_CAP_TUNE_CONFIG;
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "self-cap-tune-nvram")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_SELF_CAP_TUNE_NVRAM;
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "load")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_LOAD_CFG;
          strncpy(strbuf, optarg, sizeof(strbuf));
          strbuf[sizeof(strbuf) - 1] = '\0';
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "save")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_SAVE_CFG;
          strncpy(strbuf, optarg, sizeof(strbuf));
          strbuf[sizeof(strbuf) - 1] = '\0';
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "reset-bootloader")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_RESET_BOOTLOADER;
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "bootloader-version")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_BOOTLOADER_VERSION;
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "checksum")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_CRC_CHECK;
          strncpy(strbuf, optarg, sizeof(strbuf));
          strbuf[sizeof(strbuf) - 1] = '\0';
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "zero")) {
        if (cmd == CMD_NONE) {
          cmd = CMD_ZERO_CFG;
        } else {
          print_usage(argv[0]);
          return MXT_ERROR_BAD_INPUT;
        }
      } else if (!strcmp(long_options[option_index].name, "firmware-version")) {
        strncpy(strbuf2, optarg, sizeof(strbuf2));
      } else if (!strcmp(long_options[option_index].name, "frames")) {
        t37_frames = strtol(optarg, NULL, 0);
      } else if (!strcmp(long_options[option_index].name, "references")) {
        t37_mode = REFS_MODE;
      } else if (!strcmp(long_options[option_index].name, "self-cap-signals")) {
        t37_mode = SELF_CAP_SIGNALS;
      } else if (!strcmp(long_options[option_index].name, "self-cap-refs")) {
        t37_mode = SELF_CAP_REFS;
      } else if (!strcmp(long_options[option_index].name, "self-cap-deltas")) {
        t37_mode = SELF_CAP_DELTAS;
      } else if (!strcmp(long_options[option_index].name, "version")) {
        printf("mxt-app %s%s\n", MXT_VERSION, ENABLE_DEBUG ? " DEBUG":"");
        return MXT_SUCCESS;
      } else {
        fprintf(stderr, "Unknown option %s\n",
                long_options[option_index].name);
      }
      break;

    case 'd':
      if (optarg) {
        if (!strncmp(optarg, "i2c-dev:", 8)) {
          ret = mxt_new_conn(&conn, E_I2C_DEV);
          if (ret)
            return ret;

          if (sscanf(optarg, "i2c-dev:%d-%x",
                     &conn->i2c_dev.adapter, &conn->i2c_dev.address) != 2) {
            fprintf(stderr, "Invalid device string %s\n", optarg);
            conn = mxt_unref_conn(conn);
            return MXT_ERROR_NO_MEM;
          }
        } else if (!strncmp(optarg, "sysfs:", 6)) {
          ret = mxt_new_conn(&conn, E_SYSFS);
          if (ret)
            return ret;

          conn->sysfs.path = (char *)calloc(strlen(optarg) + 1, sizeof(char));
          if (!conn->sysfs.path) {
            fprintf(stderr, "malloc failure\n");
            conn = mxt_unref_conn(conn);
            return MXT_ERROR_NO_MEM;
          }

          memcpy(conn->sysfs.path, optarg + 6, strlen(optarg) - 6);
        }
#ifdef HAVE_LIBUSB
        else if (!strncmp(optarg, "usb:", 4)) {
          ret = mxt_new_conn(&conn, E_USB);
          if (ret)
            return ret;

          if (sscanf(optarg, "usb:%d-%d", &conn->usb.bus, &conn->usb.device) != 2) {
            fprintf(stderr, "Invalid device string %s\n", optarg);
            conn = mxt_unref_conn(conn);
            return MXT_ERROR_NO_MEM;
          }
        }
#endif
        else if (!strncmp(optarg, "hidraw:", 7)) {
          ret = mxt_new_conn(&conn, E_HIDRAW);
          if (ret)
            return ret;

          conn->hidraw.report_id = HIDRAW_REPORT_ID;

          if (sscanf(optarg, "hidraw:%s", conn->hidraw.node) != 1) {
            fprintf(stderr, "Invalid device string %s\n", optarg);
            conn = mxt_unref_conn(conn);
            return MXT_ERROR_NO_MEM;
          }
        } else {
          fprintf(stderr, "Invalid device string %s\n", optarg);
          conn = mxt_unref_conn(conn);
          return MXT_ERROR_BAD_INPUT;
        }
      }
      break;

    case 'C':
      if (cmd == CMD_NONE) {
        cmd = CMD_BRIDGE_CLIENT;
        strncpy(strbuf, optarg, sizeof(strbuf));
        strbuf[sizeof(strbuf) - 1] = '\0';
      } else {
        print_usage(argv[0]);
        return MXT_ERROR_BAD_INPUT;
      }
      break;

    case 'g':
      if (cmd == CMD_NONE) {
        cmd = CMD_GOLDEN_REFERENCES;
      } else {
        print_usage(argv[0]);
        return MXT_ERROR_BAD_INPUT;
      }
      break;

    case 'h':
      print_usage(argv[0]);
      return MXT_SUCCESS;

    case 'f':
      format = true;
      break;

    case 'I':
      if (optarg) {
        instance = strtol(optarg, NULL, 0);
      }
      break;

    case 'M':
      msgs_enabled = true;
      if (cmd == CMD_NONE) {
        cmd = CMD_MESSAGES;
      }
      if (optarg)
        msgs_timeout = strtol(optarg, NULL, 0);
      break;

    case 'F':
      if (optarg) {
        msg_filter_type = strtol(optarg, NULL, 0);
      }
      break;

    case 'n':
      if (optarg) {
        count = strtol(optarg, NULL, 0);
      }
      break;

    case 'p':
      if (optarg) {
        port = strtol(optarg, NULL, 0);
      }
      break;

    case 'q':
      if (cmd == CMD_NONE) {
        cmd = CMD_QUERY;
      } else {
        print_usage(argv[0]);
        return MXT_ERROR_BAD_INPUT;
      }
      break;

    case 'r':
      if (optarg) {
        address = strtol(optarg, NULL, 0);
      }
      break;

    case 'R':
      if (cmd == CMD_NONE) {
        cmd = CMD_READ;
      } else {
        print_usage(argv[0]);
        return MXT_ERROR_BAD_INPUT;
      }
      break;

    case 'S':
      if (cmd == CMD_NONE) {
        cmd = CMD_BRIDGE_SERVER;
      } else {
        print_usage(argv[0]);
        return MXT_ERROR_BAD_INPUT;
      }
      break;

    case 'T':
      if (optarg) {
        object_type = strtol(optarg, NULL, 0);
      }
      break;

    case 'i':
      if (cmd == CMD_NONE) {
        cmd = CMD_INFO;
      } else {
        print_usage(argv[0]);
        return MXT_ERROR_BAD_INPUT;
      }
      break;

    case 't':
      if (cmd == CMD_NONE) {
        if (optarg) {
          ret = mxt_convert_hex(optarg, &databuf, &count, sizeof(databuf));
          if (ret) {
            fprintf(stderr, "Hex convert error\n");
            ret = MXT_ERROR_BAD_INPUT;
          } else {
            self_test_cmd = databuf;
          }
        }
        cmd = CMD_TEST;
      } else {
        print_usage(argv[0]);
        return MXT_ERROR_BAD_INPUT;
      }
      break;

    case 'v':
      if (optarg) {
        verbose = strtol(optarg, NULL, 0);
      }
      break;

    case 'W':
      if (cmd == CMD_NONE) {
        cmd = CMD_WRITE;
      } else {
        print_usage(argv[0]);
        return MXT_ERROR_BAD_INPUT;
      }
      break;

    default:
      /* Output newline to create space under getopt error output */
      fprintf(stderr, "\n\n");
      print_usage(argv[0]);
      return MXT_ERROR_BAD_INPUT;
    }
  }

  struct mxt_device *mxt = NULL;
  struct libmaxtouch_ctx *ctx;

  ret = mxt_new(&ctx);
  if (ret) {
    mxt_err(ctx, "Failed to init libmaxtouch");
    return ret;
  }

  /* Set debug level */
  mxt_set_log_level(ctx, verbose);
  mxt_verb(ctx, "verbose:%u", verbose);

  /* Debug does not work until mxt_set_verbose() is called */
  mxt_info(ctx, "Version:%s", MXT_VERSION);

  if (cmd == CMD_WRITE || cmd == CMD_READ) {
    mxt_verb(ctx, "instance:%u", instance);
    mxt_verb(ctx, "count:%u", count);
    mxt_verb(ctx, "address:%u", address);
    mxt_verb(ctx, "object_type:%u", object_type);
    mxt_verb(ctx, "format:%s", format ? "true" : "false");
  }

  if (cmd == CMD_QUERY) {
    ret = mxt_scan(ctx, &conn, true);
    goto free;

  } else if (cmd != CMD_FLASH && cmd != CMD_BOOTLOADER_VERSION) {
    ret = mxt_init_chip(ctx, &mxt, &conn);
    if (ret && cmd != CMD_CRC_CHECK )
      goto free;

    if (mxt)
      mxt_set_debug(mxt, true);
  }

  switch (cmd) {
  case CMD_WRITE:
    mxt_verb(ctx, "Write command");
    ret = mxt_handle_write_cmd(mxt, object_type, count, instance, address,
                               argc, argv);
    if (ret == MXT_ERROR_BAD_INPUT)
      goto free;
    break;

  case CMD_READ:
    mxt_verb(ctx, "Read command");
    ret = mxt_read_object(mxt, object_type, instance, address, count, format);
    break;

  case CMD_INFO:
    mxt_verb(ctx, "CMD_INFO");
    mxt_print_info_block(mxt);
    ret = MXT_SUCCESS;
    break;

  case CMD_GOLDEN_REFERENCES:
    mxt_verb(ctx, "CMD_GOLDEN_REFERENCES");
    ret = mxt_store_golden_refs(mxt);
    break;

  case CMD_BRIDGE_SERVER:
    mxt_verb(ctx, "CMD_BRIDGE_SERVER");
    mxt_verb(ctx, "port:%u", port);
    ret = mxt_socket_server(mxt, port);
    break;

  case CMD_BRIDGE_CLIENT:
    mxt_verb(ctx, "CMD_BRIDGE_CLIENT");
    ret = mxt_socket_client(mxt, strbuf, port);
    break;

  case CMD_SERIAL_DATA:
    mxt_verb(ctx, "CMD_SERIAL_DATA");
    mxt_verb(ctx, "t68_datatype:%u", t68_datatype);
    ret = mxt_serial_data_upload(mxt, strbuf, t68_datatype);
    break;

  case CMD_TEST:
    mxt_verb(ctx, "CMD_TEST");
    ret = run_self_tests(mxt, self_test_cmd);
    break;

  case CMD_FLASH:
    mxt_verb(ctx, "CMD_FLASH");
    ret = mxt_flash_firmware(ctx, mxt, strbuf, strbuf2, conn);
    break;

  case CMD_RESET:
    mxt_verb(ctx, "CMD_RESET");
    ret = mxt_reset_chip(mxt, false);
    break;

  case CMD_RESET_BOOTLOADER:
    mxt_verb(ctx, "CMD_RESET_BOOTLOADER");
    ret = mxt_reset_chip(mxt, true);
    break;

  case CMD_BOOTLOADER_VERSION:
    mxt_verb(ctx, "CMD_RESET_BOOTLOADER");
    ret = mxt_bootloader_version(ctx, mxt, conn);
    break;

  case CMD_MESSAGES:
    // Messages handled after switch
    break;

  case CMD_BACKUP:
    mxt_verb(ctx, "CMD_BACKUP");
    ret = mxt_backup_config(mxt, backup_cmd);
    break;

  case CMD_CALIBRATE:
    mxt_verb(ctx, "CMD_CALIBRATE");
    ret = mxt_calibrate_chip(mxt);
    break;

  case CMD_DEBUG_DUMP:
    mxt_verb(ctx, "CMD_DEBUG_DUMP");
    mxt_verb(ctx, "mode:%u", t37_mode);
    mxt_verb(ctx, "frames:%u", t37_frames);
    ret = mxt_debug_dump(mxt, t37_mode, strbuf, t37_frames);
    break;

  case CMD_ZERO_CFG:
    mxt_verb(ctx, "CMD_ZERO_CFG");
    ret = mxt_zero_config(mxt);
    if (ret)
      mxt_err(ctx, "Error zeroing all configuration settings");
    break;

  case CMD_LOAD_CFG:
    mxt_verb(ctx, "CMD_LOAD_CFG");
    mxt_verb(ctx, "filename:%s", strbuf);
    ret = mxt_load_config_file(mxt, strbuf);
    if (ret) {
      mxt_err(ctx, "Error loading the configuration");
    } else {
      mxt_info(ctx, "Configuration loaded");

      ret = mxt_backup_config(mxt, backup_cmd);
      if (ret) {
        mxt_err(ctx, "Error backing up");
      } else {
        mxt_info(ctx, "Configuration backed up");

        ret = mxt_reset_chip(mxt, false);
        if (ret) {
          mxt_err(ctx, "Error resetting");
        } else {
          mxt_info(ctx, "Chip reset");
        }
      }
    }
    break;

  case CMD_SAVE_CFG:
    mxt_verb(ctx, "CMD_SAVE_CFG");
    mxt_verb(ctx, "filename:%s", strbuf);
    ret = mxt_save_config_file(mxt, strbuf);
    break;

  case CMD_SELF_CAP_TUNE_CONFIG:
  case CMD_SELF_CAP_TUNE_NVRAM:
    mxt_verb(ctx, "CMD_SELF_CAP_TUNE");
    ret = mxt_self_cap_tune(mxt, cmd);
    break;

  case CMD_CRC_CHECK:
    mxt_verb(ctx, "CMD_CRC_CHECK");
    mxt_verb(ctx, "filename:%s", strbuf);
    ret = mxt_checkcrc(ctx, mxt, strbuf);
    break;

  case CMD_NONE:
  default:
    mxt_verb(ctx, "cmd: %d", cmd);
    mxt_set_log_fn(ctx, mxt_log_stdout);

    if (verbose <= 2)
      mxt_set_log_level(ctx, 2);

    ret = mxt_menu(mxt);
    break;
  }

  if (cmd == CMD_MESSAGES || (msgs_enabled && ret == MXT_SUCCESS)) {
    mxt_verb(ctx, "CMD_MESSAGES");
    mxt_verb(ctx, "msgs_timeout:%d", msgs_timeout);
    // Support message filtering with -T
    if (cmd == CMD_MESSAGES && !msg_filter_type)
      msg_filter_type = object_type;

    ret = print_raw_messages(mxt, msgs_timeout, msg_filter_type);
  }

  if (cmd != CMD_FLASH && cmd != CMD_BOOTLOADER_VERSION && mxt) {
    mxt_set_debug(mxt, false);
    mxt_free_device(mxt);
    mxt_unref_conn(conn);
  }

free:
  mxt_free(ctx);

  return ret;
}
Example #3
0
//******************************************************************************
/// \brief Run self cap tuning procedure without updating the config
/// checksum
/// \return #mxt_rc
int mxt_self_cap_tune(struct mxt_device *mxt, mxt_app_cmd cmd)
{
  int ret;
  uint16_t t6_addr;
  uint16_t t109_addr;
  uint8_t backupnv_value;
  uint8_t t109_command;

  mxt_msg_reset(mxt);

  // Enable self test object & reporting
  t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
  if (t6_addr == OBJECT_NOT_FOUND)
    return MXT_ERROR_OBJECT_NOT_FOUND;

  t109_addr = mxt_get_object_address(mxt, SPT_SELFCAPGLOBALCONFIG_T109, 0);
  if (t109_addr == OBJECT_NOT_FOUND)
    return MXT_ERROR_OBJECT_NOT_FOUND;

  mxt_info(mxt->ctx, "Stopping T70");
  backupnv_value = 0x33;
  ret = mxt_write_register(mxt, &backupnv_value, t6_addr + MXT_T6_BACKUPNV_OFFSET, 1);
  if (ret)
    return ret;

  // Wait for backup operation to complete (otherwise T109 report may be missed)
  mxt_msg_wait(mxt, 100);

  mxt_info(mxt->ctx, "Tuning");
  t109_command = T109_CMD_TUNE;
  mxt_info(mxt->ctx, "Writing %u to T109 CMD register", cmd);
  ret = mxt_write_register(mxt, &t109_command, t109_addr + T109_CMD_OFFSET, 1);
  if (ret)
    return ret;

  ret = mxt_read_messages(mxt, T109_TIMEOUT, &t109_command, mxt_self_cap_command, (int *)&mxt_sigint_rx);
  if (ret)
    return ret;

  switch (cmd) {
  case CMD_SELF_CAP_TUNE_CONFIG:
    mxt_info(mxt->ctx, "Store to Config");
    t109_command = T109_CMD_STORE_TO_CONFIG_RAM;
    break;

  default:
  case CMD_SELF_CAP_TUNE_NVRAM:
    mxt_info(mxt->ctx, "Store to NVRAM");
    t109_command = T109_CMD_STORE_TO_NVM;
    break;
  }
  mxt_info(mxt->ctx, "Writing %u to T109 CMD register", cmd);
  ret = mxt_write_register(mxt, &t109_command, t109_addr + T109_CMD_OFFSET, 1);
  if (ret)
    return ret;

  ret = mxt_read_messages(mxt, 100, (void *) &t109_command, mxt_self_cap_command, (int *)&mxt_sigint_rx);
  if (ret)
    return ret;

  mxt_info(mxt->ctx, "Saving configuration");
  ret = mxt_backup_config(mxt, BACKUPNV_COMMAND);
  if (ret)
    return ret;

  ret = mxt_reset_chip(mxt, false);
  if (ret)
    return ret;

  return MXT_SUCCESS;
}
/*!
 * @brief  Entry point for the config_loader utility.
 * @return Zero on success, negative for error.
 */
int main (int argc, char *argv[])
{
  bool override_checking = false;
  struct stat file_info;
  char *filename = NULL;

  printf("Config loader tool v. %s for Atmel maXTouch chips\n\n", VERSION);

  /* Parse input arguments */
  if (argc > 1)
  {
    filename = argv[1];

    if (argc > 2 && strcmp(argv[2], "-f") == 0)
    {
      override_checking = true;
    }
  }
  else
  {
    display_usage();
    return -1;
  }

  /* Check configuration file exists */
  if (stat(filename, &file_info) != 0)
  {
    printf("Specified file does not exist\n\n");
    display_usage();
    return -1;
  }

  /* Find an mXT device and read the info block */
  switch (mxt_scan())
  {
    case 1:
      /* Device found - continue */
      break;
    case 0:
      printf("Could not find a device, exiting...\n");
      return -1;
    default:
      printf("Error initializing, exiting...\n");
      return -1;
  }

  if (mxt_get_info() < 0)
  {
    printf("Error reading info\n");
    return -1;
  }

  /* Load and back-up the configuration file */
  if (mxt_load_config_file(filename, override_checking) < 0)
  {
    printf("Error loading the configuration, exiting...\n");
    mxt_release();
    return -1;
  }
  printf("Configuration loaded\n");

  if (mxt_backup_config() < 0)
  {
    printf("Error backing up, exiting...\n");
    mxt_release();
    return -1;
  }
  printf("Configuration backed up\n");

  /* Reset the chip to apply new configuration */
  if (mxt_reset_chip(false) < 0)
  {
    printf("Error reseting, exiting...\n");
    mxt_release();
    return -1;
  }
  printf("Chip reset\n");
  mxt_release();

  printf("\nConfiguration file loader ran successfully\n");

  return 0;
}