Example #1
0
//******************************************************************************
/// \brief  Perform fallback reset
/// \return #mxt_rc
static int mxt_send_reset_command(struct mxt_device *mxt, bool bootloader_mode)
{
  int ret;
  uint16_t t6_addr;
  unsigned char write_value = RESET_COMMAND;

  /* Obtain command processor's address */
  t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
  if (t6_addr == OBJECT_NOT_FOUND)
    return MXT_ERROR_OBJECT_NOT_FOUND;

  /* The value written determines which mode the chip will boot into */
  if (bootloader_mode) {
    mxt_info(mxt->ctx, "Resetting in bootloader mode");
    write_value = BOOTLOADER_COMMAND;
  } else {
    mxt_info(mxt->ctx, "Sending reset command");
  }

  /* Write to command processor register to perform command */
  ret = mxt_write_register
        (
          mxt, &write_value, t6_addr + MXT_T6_RESET_OFFSET, 1
        );

  return ret;
}
Example #2
0
//******************************************************************************
/// \brief Print T25 limits for each enabled touch object
static void print_t25_limits(struct mxt_device *mxt, uint16_t t25_addr)
{
   int i;
   struct mxt_object obj;
   int touch_object = 0;
   uint8_t buf[4];
   uint16_t upsiglim;
   uint16_t losiglim;
   int instance;

   for (i = 0; i < mxt->info.id->num_objects; i++)
   {
      obj = mxt->info.objects[i];

      switch (obj.type)
      {
      case TOUCH_MULTITOUCHSCREEN_T9:
      case TOUCH_SINGLETOUCHSCREEN_T10:
      case TOUCH_XSLIDER_T11:
      case TOUCH_YSLIDER_T12:
      case TOUCH_XWHEEL_T13:
      case TOUCH_YWHEEL_T14:
      case TOUCH_KEYARRAY_T15:
      case TOUCH_PROXIMITY_T23:
      case TOUCH_KEYSET_T31:
      case TOUCH_XSLIDERSET_T32:
         for (instance = 0; (instance < MXT_INSTANCES(obj)); instance++)
         {
            mxt_read_register(mxt, (uint8_t *)&buf, mxt_get_start_position(obj, instance), 1);

            mxt_info(mxt->ctx, "%s[%d] %s",
                   mxt_get_object_name(obj.type),
                   instance,
                   buf[0] & 0x01 ? "enabled":"disabled");

            mxt_read_register(mxt, (uint8_t *)&buf,
               t25_addr + 2 + touch_object * 4, 4);

            upsiglim = (uint16_t)((buf[1] << 8u) | buf[0]);
            losiglim = (uint16_t)((buf[3] << 8u) | buf[2]);

            mxt_info(mxt->ctx, "  UPSIGLIM:%d", upsiglim);
            mxt_info(mxt->ctx, "  LOSIGLIM:%d", losiglim);

            touch_object++;
         }
         break;
      default:
         break;
      }
   }
   
}
Example #3
0
//******************************************************************************
/// \brief Read and deal with incoming command
/// \return #mxt_rc
static int handle_cmd(struct mxt_device *mxt, int sockfd)
{
  int ret;
  uint16_t address;
  uint16_t count;
  struct mxt_buffer linebuf;
  char *line;
  int offset;

  ret = mxt_buf_init(&linebuf);
  if (ret)
    return ret;

  ret = readline(mxt, sockfd, &linebuf);
  if (ret) {
    mxt_dbg(mxt->ctx, "Error reading or peer closed socket");
    goto free;
  }

  line = (char *)linebuf.data;
  if (strlen(line) == 0) {
    ret = MXT_SUCCESS;
    goto free;
  }

  mxt_verb(mxt->ctx, "%s", line);

  if (!strcmp(line, "SAT")) {
    mxt_info(mxt->ctx, "Server attached");
    ret = MXT_SUCCESS;
  } else if (!strcmp(line, "SDT")) {
    mxt_info(mxt->ctx, "Server detached");
    ret = MXT_SUCCESS;
  } else if (sscanf(line, "REA %" SCNu16 " %" SCNu16, &address, &count) == 2) {
    ret = bridge_rea_cmd(mxt, sockfd, address, count);
  } else if (sscanf(line, "WRI %" SCNu16 "%n", &address, &offset) == 1) {
    /* skip space */
    offset += 1;

    ret = bridge_wri_cmd(mxt, sockfd, address,
                         line + offset,
                         strlen(line) - offset);
  } else {
    mxt_info(mxt->ctx, "Unrecognised cmd \"%s\"", line);
    ret = MXT_SUCCESS;
  }

free:
  mxt_buf_free(&linebuf);
  return ret;
}
Example #4
0
/*!
 * @brief  Logs information about the chip.
 */
void mxt_display_chip_info(struct mxt_device *mxt)
{
  struct mxt_object obj;
  char firmware_version[MXT_FW_VER_LEN];
  struct mxt_id_info *id = mxt->info.id;
  int i;

  mxt_get_firmware_version(mxt, (char *)&firmware_version);

  /* Display ID information */
  mxt_info(mxt->ctx, "Family ID = %u (0x%02X)",
      id->family, id->family);
  mxt_info(mxt->ctx, "Variant ID = %u (0x%02X)",
      id->variant, id->variant);
  mxt_info(mxt->ctx, "Firmware Version = %s", firmware_version);
  mxt_info(mxt->ctx, "Matrix X Size = %d", id->matrix_x_size);
  mxt_info(mxt->ctx, "Matrix Y Size = %d", id->matrix_y_size);
  mxt_info(mxt->ctx, "Number of elements in the Object Table = %d",
      id->num_objects);

  /* Display information about specific objects */
  for (i = 0; i < id->num_objects; i++)
  {
    obj = mxt->info.objects[i];

    mxt_info(mxt->ctx, "T%u size:%u instances:%u address:%u",
      obj.type, MXT_SIZE(obj),
      MXT_INSTANCES(obj), mxt_get_start_position(obj, 0));
  }
}
Example #5
0
//******************************************************************************
/// \brief Write DATATYPE
/// \return #mxt_rc
static int mxt_t68_write_datatype(struct t68_ctx *ctx)
{
  uint8_t buf[2];

  buf[0] = (ctx->t68_datatype & 0xFF);
  buf[1] = (ctx->t68_datatype & 0xFF00) >> 8;

  mxt_info(ctx->lc, "Writing %u to DATATYPE register", ctx->t68_datatype);
  return mxt_write_register(ctx->mxt, &buf[0], ctx->t68_addr + T68_DATATYPE, sizeof(buf));
}
Example #6
0
//******************************************************************************
/// \brief Handle bridge read
/// \return #mxt_rc
static int bridge_rea_cmd(struct mxt_device *mxt, int sockfd,
                          uint16_t address, uint16_t count)
{
  int ret;
  uint8_t *databuf;
  char *response;
  const char * const PREFIX = "RRP ";
  size_t response_len;
  int i;

  databuf = calloc(count, sizeof(uint8_t));
  if (!databuf) {
    mxt_err(mxt->ctx, "Failed to allocate memory");
    return MXT_ERROR_NO_MEM;
  }

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

  strcpy(response, PREFIX);
  ret = mxt_read_register(mxt, databuf, address, count);
  if (ret) {
    mxt_warn(mxt->ctx, "RRP ERR");
    strcpy(response + strlen(PREFIX), "ERR\n");
    response_len = strlen(response);
  } else {
    for (i = 0; i < count; i++) {
      sprintf(response + strlen(PREFIX) + i*2, "%02X", databuf[i]);
    }
    mxt_info(mxt->ctx, "%s", response);
    response[response_len - 1] = '\n';
  }

  ret = write(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);
free_databuf:
  free(databuf);
  return ret;
}
Example #7
0
//******************************************************************************
/// \brief Print T68 status messages
static void mxt_t68_print_status(struct t68_ctx *ctx, uint8_t status)
{
  mxt_info(ctx->lc, "T68 status: %02X %s%s%s%s%s%s%s",
           status,
           (status == 0x00) ? "Success/No error" : "",
           (status == 0x01) ? "Command supplied in CMD.COMMAND is out of sequence" : "",
           (status == 0x02) ? "Supplied DATATYPE value is not supported" : "",
           (status == 0x03) ? "Supplied LENGTH value exceeds length of DATA[] array" : "",
           (status == 0x04) ? "More bytes supplied than can be accommodated by this data type" : "",
           (status == 0x05) ? "Data content is invalid" : "",
           (status == 0x0F) ? "The action could not be completed due to an error outside of this object" : "");
}
Example #8
0
//******************************************************************************
/// \brief Run self test
int run_self_tests(struct mxt_device *mxt, uint8_t cmd)
{
   uint16_t t25_addr;
   uint8_t enable = 3;

   mxt_msg_reset(mxt);

   // Enable self test object & reporting
   t25_addr = mxt_get_object_address(mxt, SPT_SELFTEST_T25, 0);
   mxt_info(mxt->ctx, "Enabling self test object");
   mxt_write_register(mxt, &enable, t25_addr, 1);

   mxt_info(mxt->ctx, "Disabling noise suppression");
   disable_noise_suppression(mxt);

   print_t25_limits(mxt, t25_addr);

   mxt_info(mxt->ctx, "Running tests");
   mxt_write_register(mxt, &cmd, t25_addr + 1, 1);

   return self_test_handle_messages(mxt);
}
Example #9
0
//******************************************************************************
/// \brief Send frames of T68 data to chip
/// \return #mxt_rc
static int mxt_t68_send_frames(struct t68_ctx *ctx)
{
  int ret;
  size_t offset = 0;
  uint16_t frame_size;
  int frame = 1;
  uint8_t cmd;

  while (offset < ctx->buf.size) {
    frame_size = MIN(ctx->buf.size - offset, ctx->t68_data_size);

    mxt_info(ctx->lc, "Writing frame %u, %u bytes", frame, frame_size);

    if (frame_size > UCHAR_MAX) {
      mxt_err(ctx->lc, "Serial data frame size miscalculation");
      return MXT_INTERNAL_ERROR;
    }

    ret = mxt_write_register(ctx->mxt, ctx->buf.data + offset,
                             ctx->t68_addr + T68_DATA,
                             frame_size);
    if (ret)
      return ret;

    ret = mxt_t68_write_length(ctx, frame_size);
    if (ret)
      return ret;

    offset += frame_size;

    if (frame == 1)
      cmd = T68_CMD_START;
    else if (offset >= ctx->buf.size)
      cmd = T68_CMD_END;
    else
      cmd = T68_CMD_CONTINUE;

    ret = mxt_t68_command(ctx, cmd);
    if (ret)
      return ret;

    frame++;
  }

  return MXT_SUCCESS;
}
Example #10
0
//******************************************************************************
/// \brief Handle calibration messages
/// \return #mxt_rc
static int handle_calibrate_msg(struct mxt_device *mxt, uint8_t *msg,
                                void *context, uint8_t size)
{
  int *last_status = context;
  int status = msg[1];

  if (mxt_report_id_to_type(mxt, msg[0]) == GEN_COMMANDPROCESSOR_T6) {
    if (status & 0x10) {
      mxt_dbg(mxt->ctx, "Device calibrating");
    } else if (!(status & 0x10) && (*last_status & 0x10)) {
      mxt_info(mxt->ctx, "Device calibrated");
      return MXT_SUCCESS;
    }

    *last_status = status;
  }

  return MXT_MSG_CONTINUE;
}
Example #11
0
//******************************************************************************
/// \brief  Open device
/// \return #mxt_rc
int sysfs_open(struct mxt_device *mxt)
{
  struct sysfs_conn_info *conn = &mxt->conn->sysfs;
  char *filename;
  struct stat filestat;
  int ret;

  mxt->sysfs.path_max = strlen(conn->path) + 20;

  // Allocate temporary path space
  mxt->sysfs.temp_path = calloc(mxt->sysfs.path_max + 1, sizeof(char));
  if (!mxt->sysfs.temp_path)
    return MXT_ERROR_NO_MEM;

  // Cache memory access path for fast access
  mxt->sysfs.mem_access_path = calloc(mxt->sysfs.path_max + 1, sizeof(char));
  if (!mxt->sysfs.mem_access_path)
    return MXT_ERROR_NO_MEM;

  snprintf(mxt->sysfs.mem_access_path, mxt->sysfs.path_max,
           "%s/mem_access", conn->path);

  // Check whether debug v2 or not
  filename = make_path(mxt, "debug_msg");

  ret = stat(filename, &filestat);
  if (ret < 0) {
    if (errno == ENOENT) {
      mxt->sysfs.debug_v2 = false;
    } else {
      mxt_err(mxt->ctx, "Could not stat %s, error %s (%d)",
              filename, strerror(errno), errno);
      return mxt_errno_to_rc(errno);
    }
  } else {
    mxt->sysfs.debug_v2 = true;
  }

  mxt_info(mxt->ctx, "Registered sysfs path:%s", conn->path);

  return MXT_SUCCESS;
}
Example #12
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 #13
0
//******************************************************************************
/// \brief Bridge client
/// \return #mxt_rc
int mxt_socket_client(struct mxt_device *mxt, char *ip_address, uint16_t port)
{
  struct hostent *server;
  struct bridge_context bridge_ctx;
  bridge_ctx.msgs_enabled = false;
  int ret;
  struct sockaddr_in serv_addr;

  server = gethostbyname(ip_address);
  if (server == NULL) {
    mxt_err(mxt->ctx, "Error, no such host");
    return MXT_ERROR_CONNECTION_FAILURE;
  }

  bridge_ctx.sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (bridge_ctx.sockfd < 0) {
    mxt_err(mxt->ctx, "Socket error: %s (%d)", strerror(errno), errno);
    return MXT_ERROR_CONNECTION_FAILURE;
  }

  /* Set up socket options */
  bzero((char *) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  bcopy((char *)server->h_addr,
        (char *)&serv_addr.sin_addr.s_addr,
        server->h_length);
  serv_addr.sin_port = htons(port);

  /* Connect */
  mxt_info(mxt->ctx, "Connecting to %s:%u", ip_address, port);
  ret = connect(bridge_ctx.sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
  if (ret < 0) {
    mxt_err(mxt->ctx, "Connect error: %s (%d)", strerror(errno), errno);
    return MXT_ERROR_CONNECTION_FAILURE;
  }

  ret = bridge(mxt, &bridge_ctx);

  close(bridge_ctx.sockfd);
  return ret;
}
Example #14
0
//******************************************************************************
/// \brief  Backup configuration settings to non-volatile memory
/// \return #mxt_rc
int mxt_backup_config(struct mxt_device *mxt, uint8_t backup_command)
{
  int ret;
  uint16_t t6_addr;

  /* Obtain command processor's address */
  t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
  if (t6_addr == OBJECT_NOT_FOUND)
    return MXT_ERROR_OBJECT_NOT_FOUND;

  /* Write to command processor register to perform command */
  ret = mxt_write_register
        (
          mxt, &backup_command, t6_addr + MXT_T6_BACKUPNV_OFFSET, 1
        );

  if (ret == MXT_SUCCESS)
    mxt_info(mxt->ctx, "Backed up settings to the non-volatile memory");
  else
    mxt_err(mxt->ctx, "Failed to back up settings");

  return ret;
}
Example #15
0
//******************************************************************************
/// \brief  Calibrate maxtouch chip
/// \return 0 = success, negative = fail
int mxt_calibrate_chip(struct mxt_device *mxt)
{
  int ret;
  uint16_t t6_addr;
  unsigned char write_value = CALIBRATE_COMMAND;

  /* Obtain command processor's address */
  t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
  if (t6_addr == OBJECT_NOT_FOUND)
    return MXT_ERROR_OBJECT_NOT_FOUND;

  mxt_flush_msgs(mxt);

  /* Write to command processor register to perform command */
  ret = mxt_write_register(mxt, &write_value, t6_addr + MXT_T6_CALIBRATE_OFFSET, 1);
  if (ret == 0) {
    mxt_info(mxt->ctx, "Sent calibration command");
  } else {
    mxt_err(mxt->ctx, "Failed to send calibration command");
  }

  int state = 0;
  int flag = false;

  ret = mxt_read_messages(mxt, MXT_CALIBRATE_TIMEOUT, &state,
                          handle_calibrate_msg, &flag);
  if (ret == MXT_ERROR_TIMEOUT) {
    mxt_warn(mxt->ctx, "WARN: timed out waiting for calibrate status");
    return MXT_SUCCESS;
  } else if (ret) {
    mxt_err(mxt->ctx, "FAIL: device calibration failed");
    return ret;
  }

  return MXT_SUCCESS;
}
Example #16
0
//******************************************************************************
/// \brief  Issue REPORTALL command to device
/// \return #mxt_rc
int mxt_report_all(struct mxt_device *mxt)
{
  int ret;
  uint16_t t6_addr;
  const uint8_t report_all_cmd = 0xff;

  /* Obtain command processor's address */
  t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0);
  if (t6_addr == OBJECT_NOT_FOUND)
    return MXT_ERROR_OBJECT_NOT_FOUND;

  /* Write to command processor register to perform command */
  ret = mxt_write_register
        (
          mxt, &report_all_cmd, t6_addr + MXT_T6_REPORTALL_OFFSET, 1
        );

  if (ret == MXT_SUCCESS)
    mxt_info(mxt->ctx, "REPORTALL command issued");
  else
    mxt_err(mxt->ctx, "Failed to issue REPORTALL command");

  return ret;
}
Example #17
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 #18
0
//******************************************************************************
/// \brief  Read hex encoded data from file
/// \return #mxt_rc
static int mxt_t68_load_file(struct t68_ctx *ctx)
{
  int ret;
  uint8_t value = 0;
  FILE *fp;
  bool file_read = false;
  char buf[256];
  uint16_t hexcount;
  int c;

  /* open file */
  fp = fopen(ctx->filename, "r");
  if (fp == NULL) {
    mxt_err(ctx->lc, "Error opening %s", ctx->filename);
    return mxt_errno_to_rc(errno);
  }

  ret = mxt_buf_init(&ctx->buf);
  if (ret) {
    mxt_err(ctx->lc, "Error initialising buffer");
    goto close;
  }

  while (!file_read) {
    /* Read next value from file */
    c = getc(fp);
    if (c == EOF) {
      break;
    }
    /* skip spaces, newlines, commas*/
    else if (c == 0x20 || c == '\r' || c == '\n' || c == ',') {
      continue;
    }
    /* Ignore comment lines */
    else if (c == '[') {
      // Grab comment key
      if (fscanf(fp, "%255[^]]", buf) != 1) {
        ret = MXT_ERROR_FILE_FORMAT;
        goto fail;
      }

      mxt_verb(ctx->lc, "[%s]", buf);

      if (!strncasecmp(buf, "datatype=", 9)) {
        if (sscanf(buf + 9, "%d", &c) != 1) {
          mxt_warn(ctx->lc, "Unable to parse datatype");
        } else {
          ctx->t68_datatype = c;
          mxt_info(ctx->lc, "DATATYPE set to %u by file", ctx->t68_datatype);
        }
      }

      // Read until end of line
      while (c != '\n') {
        c = getc(fp);
      }
      continue;
    }
    /* A value looks like "0xABu," */
    else if (c == '0') {
      if (fscanf(fp, "x%2su", (char *)&buf) != 1) {
        mxt_err(ctx->lc, "Parse error");
        ret = MXT_ERROR_FILE_FORMAT;
        goto fail;
      }

      ret = mxt_convert_hex(buf, &value, &hexcount, 3);
      if (ret)
        goto fail;

      ret = mxt_buf_add(&ctx->buf, value);
      if (ret)
        goto fail;
    } else {
      mxt_err(ctx->lc, "Unexpected character \"%c\"", c);
      ret = MXT_ERROR_FILE_FORMAT;
      goto fail;
    }
  }

  mxt_info(ctx->lc, "Loaded file %s, %zu bytes", ctx->filename, ctx->buf.size);

  return MXT_SUCCESS;

fail:
  mxt_buf_free(&ctx->buf);
close:
  fclose(fp);
  return ret;
}
Example #19
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;
}
Example #20
0
//******************************************************************************
/// \brief Main bridge function to handle a single connection
/// \return #mxt_rc
static int bridge(struct mxt_device *mxt, int sockfd)
{
  int ret, pollret;
  struct pollfd fds[2];
  int fopts = 0;
  int debug_ng_fd = 0;
  int numfds = 1;
  int timeout;

  mxt_info(mxt->ctx, "Connected");

  ret = mxt_msg_reset(mxt);
  if (ret)
    mxt_err(mxt->ctx, "Failure to reset msgs");

  fds[0].fd = sockfd;
  fds[0].events = POLLIN | POLLERR;

  ret = send_chip_attach(mxt, sockfd);
  if (ret)
    return ret;

  while (1) {
    debug_ng_fd = mxt_get_msg_poll_fd(mxt);
    if (debug_ng_fd) {
      fds[1].fd = debug_ng_fd;
      fds[1].events = POLLPRI;
      numfds = 2;
      timeout = -1;
    } else {
      timeout = 100; // milliseconds
    }

    pollret = poll(fds, numfds, timeout);
    if (pollret == -1 && errno == EINTR) {
      mxt_dbg(mxt->ctx, "Interrupted");
      continue;
    } else if (pollret == -1) {
      mxt_err(mxt->ctx, "Poll returned %d (%s)", errno, strerror(errno));
      ret = mxt_errno_to_rc(errno);
      goto disconnect;
    }

    /* Detect socket disconnect */
    if (fcntl(sockfd, F_GETFL, &fopts) < 0) {
      ret = MXT_SUCCESS;
      mxt_dbg(mxt->ctx, "Socket disconnected");
      goto disconnect;
    }

    if (fds[0].revents) {
      ret = handle_cmd(mxt, sockfd);
      if (ret) {
        mxt_dbg(mxt->ctx, "handle_cmd returned %d", ret);
        goto disconnect;
      }
    }

    /* If timeout or msg poll fd event */
    if (pollret == 0 || fds[1].revents) {
      ret = handle_messages(mxt, sockfd);
      if (ret)
        goto disconnect;
    }
  }

disconnect:
  mxt_info(mxt->ctx, "Disconnected");
  return ret;
}
Example #21
0
//******************************************************************************
/// \brief Upload file to T68 Serial Data Object
/// \return #mxt_rc
int mxt_serial_data_upload(struct mxt_device *mxt, const char *filename, uint16_t datatype)
{
  int ret;
  struct t68_ctx ctx;

  ctx.mxt = mxt;
  ctx.lc = mxt->ctx;

  ret = mxt_msg_reset(mxt);
  if (ret)
    return ret;

  mxt_info(ctx.lc, "Checking T7 Power Config");
  ret = mxt_t68_check_power_cfg(&ctx);
  if (ret)
    return ret;

  /* Check for existence of T68 object */
  ctx.t68_addr = mxt_get_object_address(mxt, SERIAL_DATA_COMMAND_T68, 0);
  if (ctx.t68_addr == OBJECT_NOT_FOUND)
    return MXT_ERROR_OBJECT_NOT_FOUND;

  /* Calculate position of CMD register */
  ctx.t68_size = mxt_get_object_size(mxt, SERIAL_DATA_COMMAND_T68);
  ctx.t68_cmd_addr = ctx.t68_addr + ctx.t68_size - 3;

  /* Calculate frame size */
  ctx.t68_data_size = ctx.t68_size - 9;

  /* Set datatype from command line */
  ctx.t68_datatype = datatype;

  /* Read input file */
  ctx.filename = filename;
  ret = mxt_t68_load_file(&ctx);
  if (ret)
    return ret;

  ret = mxt_t68_enable(&ctx);
  if (ret)
    goto release;

  ret = mxt_t68_zero_data(&ctx);
  if (ret)
    goto release;

  ret = mxt_t68_write_length(&ctx, 0);
  if (ret)
    goto release;

  mxt_info(ctx.lc, "Configuring T68");
  ret = mxt_t68_write_datatype(&ctx);
  if (ret)
    goto release;

  mxt_info(ctx.lc, "Sending data");
  ret = mxt_t68_send_frames(&ctx);
  if (ret) {
    mxt_err(ctx.lc, "Error sending data");
    goto release;
  }

  mxt_info(ctx.lc, "Done");
  ret = MXT_SUCCESS;

release:
  mxt_buf_free(&ctx.buf);
  return ret;
}
Example #22
0
//******************************************************************************
/// \brief Retrieve data from the T37 Diagnostic Data object
/// \return #mxt_rc
int mxt_debug_dump(struct mxt_device *mxt, int mode, const char *csv_file,
                   uint16_t frames)
{
  struct t37_ctx ctx;
  time_t t1;
  time_t t2;
  int ret;

  ctx.lc = mxt->ctx;
  ctx.mxt = mxt;
  ctx.mode = mode;

  if (frames == 0) {
    mxt_warn(ctx.lc, "Defaulting to 1 frame");
    frames = 1;
  }

  ret = mxt_debug_dump_initialise(&ctx);
  if (ret)
    return ret;

  /* Open Hawkeye output file */
  ctx.hawkeye = fopen(csv_file,"w");
  if (!ctx.hawkeye) {
    mxt_err(ctx.lc, "Failed to open file!");
    ret = MXT_ERROR_IO;
    goto free;
  }

  ret = mxt_generate_hawkeye_header(&ctx);
  if (ret)
    goto close;

  mxt_info(ctx.lc, "Reading %u frames", frames);

  t1 = time(NULL);

  for (ctx.frame = 1; ctx.frame <= frames; ctx.frame++) {
    if (ctx.self_cap) {
      ret = mxt_read_diagnostic_data_self_cap(&ctx);
    }
    else if (ctx.active_stylus){
      ret = mxt_read_diagnostic_data_ast(&ctx);
    } else {
      ret = mxt_read_diagnostic_data_frame(&ctx);
    }
    if (ret)
      goto close;

    ret = mxt_hawkeye_output(&ctx);
    if (ret)
      goto close;
  }

  t2 = time(NULL);
  mxt_info(ctx.lc, "%u frames in %d seconds", frames, (int)(t2-t1));

  ret = MXT_SUCCESS;

close:
  fclose(ctx.hawkeye);
free:
  free(ctx.data_buf);
  ctx.data_buf = NULL;
  free(ctx.t37_buf);
  ctx.t37_buf = NULL;

  return ret;
}
Example #23
0
//******************************************************************************
/// \brief  Register hidraw device
/// \return #mxt_rc
int hidraw_register(struct mxt_device *mxt)
{
  mxt_info(mxt->ctx, "Registered hidraw adapter:%s", mxt->conn->hidraw.node );

  return MXT_SUCCESS;
}
Example #24
0
//******************************************************************************
/// \brief Handle messages from the self test object
/// \return #mxt_rc
static int self_test_handle_messages(struct mxt_device *mxt)
{
   bool done = false;
   int count, i;
   time_t now;
   time_t start_time = time(NULL);
   static const uint8_t TIMEOUT = 10; // seconds
   uint8_t buf[10];
   int len;
   unsigned int object_type;
   int ret;

   while (!done)
   {
      mxt_msg_wait(mxt, 100);

      now = time(NULL);
      if ((now - start_time) > TIMEOUT)
      {
         mxt_err(mxt->ctx, "Timeout");
         return MXT_ERROR_TIMEOUT;
      }

      ret = mxt_get_msg_count(mxt, &count);
      if (ret)
        return ret;

      if (count > 0)
      {
         for (i = 0; i < count; i++)
         {
            ret = mxt_get_msg_bytes(mxt, buf, sizeof(buf), &len);
            if (ret)
              return ret;

            if (len > 0)
            {
               object_type = mxt_report_id_to_type(mxt, buf[0]);

               mxt_verb(mxt->ctx, "Received message from T%u", object_type);
               
               if (object_type == SPT_SELFTEST_T25)
               {
                  switch (buf[1])
                  {
                  case SELF_TEST_ALL:
                     mxt_info(mxt->ctx, "PASS: All tests passed");
                     ret = MXT_SUCCESS;
                     break;
                  case SELF_TEST_INVALID:
                     mxt_err(mxt->ctx, "FAIL: Invalid test command");
                     ret = MXT_ERROR_NOT_SUPPORTED;
                     break;
                  case SELF_TEST_TIMEOUT:
                     mxt_err(mxt->ctx, "FAIL: Test timeout");
                     ret = MXT_ERROR_TIMEOUT;
                     break;
                  case SELF_TEST_ANALOG:
                     mxt_err(mxt->ctx, "FAIL: AVdd Analog power is not present");
                     ret = MXT_ERROR_SELF_TEST_ANALOG;
                     break;
                  case SELF_TEST_PIN_FAULT:
                     mxt_err(mxt->ctx, "FAIL: Pin fault");
                     ret = MXT_ERROR_SELF_TEST_PIN_FAULT;
                     break;
                  case SELF_TEST_PIN_FAULT_2:
                     mxt_err(mxt->ctx, "FAIL: Pin fault 2");
                     ret = MXT_ERROR_SELF_TEST_PIN_FAULT;
                     break;
                  case SELF_TEST_AND_GATE:
                     mxt_err(mxt->ctx, "FAIL: AND Gate Fault");
                     ret = MXT_ERROR_SELF_TEST_AND_GATE;
                     break;
                  case SELF_TEST_SIGNAL_LIMIT:
                     mxt_err(mxt->ctx, "FAIL: Signal limit fault");
                     ret = MXT_ERROR_SELF_TEST_SIGNAL_LIMIT;
                     break;
                  case SELF_TEST_GAIN:
                     mxt_err(mxt->ctx, "FAIL: Gain error");
                     ret = MXT_ERROR_SELF_TEST_GAIN;
                     break;
                  default:
                     mxt_err(mxt->ctx, "Unrecognised status %02X", buf[1]);
                     ret = MXT_ERROR_UNEXPECTED_DEVICE_STATE;
                     break;
                  }

                  done = true;
               }
            }
         }
      }
   }

   return ret;
}
Example #25
0
//******************************************************************************
/// \brief Read and deal with incoming command
/// \return #mxt_rc
static int handle_cmd(struct mxt_device *mxt, struct bridge_context *bridge_ctx)
{
  int ret;
  uint16_t address;
  uint16_t count;
  struct mxt_buffer linebuf;
  char *line;
  int offset;

  ret = mxt_buf_init(&linebuf);
  if (ret)
    return ret;

  ret = readline(mxt, bridge_ctx->sockfd, &linebuf);
  if (ret) {
    mxt_dbg(mxt->ctx, "Error reading or peer closed socket");
    goto free;
  }

  line = (char *)linebuf.data;
  if (strlen(line) == 0) {
    ret = MXT_SUCCESS;
    goto free;
  }

  mxt_verb(mxt->ctx, "%s", line);

  if (!strcmp(line, "SAT")) {
    mxt_info(mxt->ctx, "Server attached");
    ret = MXT_SUCCESS;
  } else if (!strcmp(line, "SDT")) {
    mxt_info(mxt->ctx, "Server detached");
    ret = MXT_SUCCESS;
  } else if (sscanf(line, "REA %" SCNu16 " %" SCNu16, &address, &count) == 2) {
    ret = bridge_rea_cmd(mxt, bridge_ctx, address, count);
  } else if (sscanf(line, "WRI %" SCNu16 "%n", &address, &offset) == 1) {
    /* skip space */
    offset += 1;

    ret = bridge_wri_cmd(mxt, bridge_ctx, address,
                         line + offset,
                         strlen(line) - offset);
  } else if (sscanf(line, "RST %" SCNu16 "%n", &address, &offset) == 1) {
    ret = bridge_handle_reset(mxt, bridge_ctx, address);
    ret = MXT_SUCCESS;
  } else if (sscanf(line, "MSGCFG %" SCNu16 "%n", &address, &offset) == 1) {
    mxt_info(mxt->ctx, "Configuring Messages");
    bridge_ctx->msgs_enabled = true;
    const char * const msg = "MSGCFG OK\n";

    ret = write(bridge_ctx->sockfd, msg, strlen(msg));
    if (ret < 0) {
      mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno);
      ret = mxt_errno_to_rc(errno);
    }
    ret = MXT_SUCCESS;
  } else {
    mxt_info(mxt->ctx, "Unrecognised cmd \"%s\"", line);
    ret = MXT_SUCCESS;
  }

free:
  mxt_buf_free(&linebuf);
  return ret;
}