qcdm: implement command handling and minimal infrastructure
This commit is contained in:
@@ -5,6 +5,16 @@ libqcdm_la_CPPFLAGS = \
|
||||
$(MM_CFLAGS)
|
||||
|
||||
libqcdm_la_SOURCES = \
|
||||
dm-commands.h \
|
||||
com.c \
|
||||
com.h \
|
||||
commands.c \
|
||||
commands.h \
|
||||
error.c \
|
||||
error.h \
|
||||
result.c \
|
||||
result.h \
|
||||
result-private.h \
|
||||
utils.c \
|
||||
utils.h
|
||||
|
||||
|
62
libqcdm/src/com.c
Normal file
62
libqcdm/src/com.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <termio.h>
|
||||
|
||||
#include "com.h"
|
||||
#include "error.h"
|
||||
|
||||
gboolean
|
||||
qcdm_port_setup (int fd, GError **error)
|
||||
{
|
||||
struct termio stbuf;
|
||||
|
||||
g_type_init ();
|
||||
|
||||
errno = 0;
|
||||
memset (&stbuf, 0, sizeof (struct termio));
|
||||
if (ioctl (fd, TCGETA, &stbuf) != 0) {
|
||||
g_set_error (error,
|
||||
QCDM_SERIAL_ERROR, QCDM_SERIAL_CONFIG_FAILED,
|
||||
"TCGETA error: %d", errno);
|
||||
}
|
||||
|
||||
stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
|
||||
stbuf.c_iflag &= ~(HUPCL | IUTF8 | IUCLC | ISTRIP | IXON | ICRNL);
|
||||
stbuf.c_oflag &= ~(OPOST | OCRNL | ONLCR | OLCUC | ONLRET);
|
||||
stbuf.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL);
|
||||
stbuf.c_lflag &= ~(NOFLSH | XCASE | TOSTOP | ECHOPRT | ECHOCTL | ECHOKE);
|
||||
stbuf.c_cc[VMIN] = 1;
|
||||
stbuf.c_cc[VTIME] = 0;
|
||||
stbuf.c_cc[VEOF] = 1;
|
||||
stbuf.c_cflag |= (B115200 | CS8 | CREAD | 0 | 0); /* No parity, 1 stop bit */
|
||||
|
||||
errno = 0;
|
||||
if (ioctl (fd, TCSETA, &stbuf) < 0) {
|
||||
g_set_error (error,
|
||||
QCDM_SERIAL_ERROR, QCDM_SERIAL_CONFIG_FAILED,
|
||||
"TCSETA error: %d", errno);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
25
libqcdm/src/com.h
Normal file
25
libqcdm/src/com.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBQCDM_COM_H
|
||||
#define LIBQCDM_COM_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
gboolean qcdm_port_setup (int fd, GError **error);
|
||||
|
||||
#endif /* LIBQCDM_COM_H */
|
108
libqcdm/src/commands.c
Normal file
108
libqcdm/src/commands.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "commands.h"
|
||||
#include "error.h"
|
||||
#include "dm-commands.h"
|
||||
#include "result-private.h"
|
||||
#include "utils.h"
|
||||
|
||||
static gboolean
|
||||
check_command (const char *buf, gsize len, guint8 cmd, gsize min_len, GError **error)
|
||||
{
|
||||
if (len < 1) {
|
||||
g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_MALFORMED_RESPONSE,
|
||||
"DM command response malformed (must be at least 1 byte in length)");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (buf[0] != (guint8) cmd) {
|
||||
g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_UNEXPECTED,
|
||||
"Unexpected DM command response (expected %d, got %d)",
|
||||
cmd, buf[0]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (len < min_len) {
|
||||
g_set_error (error, QCDM_COMMAND_ERROR, QCDM_COMMAND_BAD_LENGTH,
|
||||
"DM command %d response not long enough (got %zu, expected "
|
||||
"at least %zu).", cmd, len, min_len);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gsize
|
||||
qcdm_cmd_version_info_new (char *buf, gsize len, GError **error)
|
||||
{
|
||||
char cmdbuf[3];
|
||||
DMCmdHeader *cmd = (DMCmdHeader *) &cmdbuf[0];
|
||||
|
||||
g_return_val_if_fail (buf != NULL, 0);
|
||||
g_return_val_if_fail (len >= sizeof (*cmd) + DIAG_TRAILER_LEN, 0);
|
||||
|
||||
memset (cmd, 0, sizeof (cmd));
|
||||
cmd->code = DIAG_CMD_VERSION_INFO;
|
||||
|
||||
return dm_prepare_buffer (cmdbuf, sizeof (*cmd), sizeof (cmdbuf), buf, len);
|
||||
}
|
||||
|
||||
QCDMResult *
|
||||
qcdm_cmd_version_info_result (const char *buf, gsize len, GError **error)
|
||||
{
|
||||
QCDMResult *result = NULL;
|
||||
DMCmdVersionInfoRsp *rsp = (DMCmdVersionInfoRsp *) buf;
|
||||
char tmp[12];
|
||||
|
||||
g_return_val_if_fail (buf != NULL, NULL);
|
||||
|
||||
if (!check_command (buf, len, DIAG_CMD_VERSION_INFO, sizeof (DMCmdVersionInfoRsp), error))
|
||||
return NULL;
|
||||
|
||||
result = qcdm_result_new ();
|
||||
|
||||
memset (tmp, 0, sizeof (tmp));
|
||||
g_assert (sizeof (rsp->comp_date) <= sizeof (tmp));
|
||||
memcpy (tmp, rsp->comp_date, sizeof (rsp->comp_date));
|
||||
qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_COMP_DATE, tmp);
|
||||
|
||||
memset (tmp, 0, sizeof (tmp));
|
||||
g_assert (sizeof (rsp->comp_time) <= sizeof (tmp));
|
||||
memcpy (tmp, rsp->comp_time, sizeof (rsp->comp_time));
|
||||
qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_COMP_TIME, tmp);
|
||||
|
||||
memset (tmp, 0, sizeof (tmp));
|
||||
g_assert (sizeof (rsp->rel_date) <= sizeof (tmp));
|
||||
memcpy (tmp, rsp->rel_date, sizeof (rsp->rel_date));
|
||||
qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_RELEASE_DATE, tmp);
|
||||
|
||||
memset (tmp, 0, sizeof (tmp));
|
||||
g_assert (sizeof (rsp->rel_time) <= sizeof (tmp));
|
||||
memcpy (tmp, rsp->rel_time, sizeof (rsp->rel_time));
|
||||
qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_RELEASE_TIME, tmp);
|
||||
|
||||
memset (tmp, 0, sizeof (tmp));
|
||||
g_assert (sizeof (rsp->model) <= sizeof (tmp));
|
||||
memcpy (tmp, rsp->model, sizeof (rsp->model));
|
||||
qcdm_result_add_string (result, QCDM_CMD_VERSION_INFO_ITEM_MODEL, tmp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
39
libqcdm/src/commands.h
Normal file
39
libqcdm/src/commands.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBQCDM_COMMANDS_H
|
||||
#define LIBQCDM_COMMANDS_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "result.h"
|
||||
|
||||
gsize qcdm_cmd_version_info_new (char *buf,
|
||||
gsize len,
|
||||
GError **error);
|
||||
|
||||
#define QCDM_CMD_VERSION_INFO_ITEM_COMP_DATE "comp-date"
|
||||
#define QCDM_CMD_VERSION_INFO_ITEM_COMP_TIME "comp-time"
|
||||
#define QCDM_CMD_VERSION_INFO_ITEM_RELEASE_DATE "release-date"
|
||||
#define QCDM_CMD_VERSION_INFO_ITEM_RELEASE_TIME "release-time"
|
||||
#define QCDM_CMD_VERSION_INFO_ITEM_MODEL "model"
|
||||
|
||||
QCDMResult *qcdm_cmd_version_info_result (const char *buf,
|
||||
gsize len,
|
||||
GError **error);
|
||||
|
||||
#endif /* LIBQCDM_COMMANDS_H */
|
187
libqcdm/src/dm-commands.h
Normal file
187
libqcdm/src/dm-commands.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBQCDM_DM_COMMANDS_H
|
||||
#define LIBQCDM_DM_COMMANDS_H
|
||||
|
||||
enum {
|
||||
DIAG_CMD_VERSION_INFO = 0, /* Version info */
|
||||
DIAG_CMD_ESN = 1, /* ESN */
|
||||
DIAG_CMD_PEEKB = 2, /* Peek byte */
|
||||
DIAG_CMD_PEEKW = 3, /* Peek word */
|
||||
DIAG_CMD_PEEKD = 4, /* Peek dword */
|
||||
DIAG_CMD_POKEB = 5, /* Poke byte */
|
||||
DIAG_CMD_POKEW = 6, /* Poke word */
|
||||
DIAG_CMD_POKED = 7, /* Poke dword */
|
||||
DIAG_CMD_OUTP = 8, /* Byte output */
|
||||
DIAG_CMD_OUTPW = 9, /* Word output */
|
||||
DIAG_CMD_INP = 10, /* Byte input */
|
||||
DIAG_CMD_INPW = 11, /* Word input */
|
||||
DIAG_CMD_STATUS = 12, /* Station status */
|
||||
DIAG_CMD_LOGMASK = 15, /* Set logging mask */
|
||||
DIAG_CMD_LOG = 16, /* Log packet */
|
||||
DIAG_CMD_NV_PEEK = 17, /* Peek NV memory */
|
||||
DIAG_CMD_NV_POKE = 18, /* Poke NV memory */
|
||||
DIAG_CMD_BAD_CMD = 19, /* Invalid command (response) */
|
||||
DIAG_CMD_BAD_PARM = 20, /* Invalid parameter (response) */
|
||||
DIAG_CMD_BAD_LEN = 21, /* Invalid packet length (response) */
|
||||
DIAG_CMD_BAD_DEV = 22, /* Not accepted by the device (response) */
|
||||
DIAG_CMD_BAD_MODE = 24, /* Not allowed in this mode (response) */
|
||||
DIAG_CMD_TAGRAPH = 25, /* Info for TA power and voice graphs */
|
||||
DIAG_CMD_MARKOV = 26, /* Markov stats */
|
||||
DIAG_CMD_MARKOV_RESET = 27, /* Reset Markov stats */
|
||||
DIAG_CMD_DIAG_VER = 28, /* Diagnostic Monitor version */
|
||||
DIAG_CMD_TIMESTAMP = 29, /* Return a timestamp */
|
||||
DIAG_CMD_TA_PARM = 30, /* Set TA parameters */
|
||||
DIAG_CMD_MESSAGE = 31, /* Request for msg report */
|
||||
DIAG_CMD_HS_KEY = 32, /* Handset emulation -- keypress */
|
||||
DIAG_CMD_HS_LOCK = 33, /* Handset emulation -- lock or unlock */
|
||||
DIAG_CMD_HS_SCREEN = 34, /* Handset emulation -- display request */
|
||||
DIAG_CMD_PARM_SET = 36, /* Parameter download */
|
||||
DIAG_CMD_NV_READ = 38, /* Read NV item */
|
||||
DIAG_CMD_NV_WRITE = 39, /* Write NV item */
|
||||
DIAG_CMD_CONTROL = 41, /* Mode change request */
|
||||
DIAG_CMD_ERR_READ = 42, /* Error record retreival */
|
||||
DIAG_CMD_ERR_CLEAR = 43, /* Error record clear */
|
||||
DIAG_CMD_SER_RESET = 44, /* Symbol error rate counter reset */
|
||||
DIAG_CMD_SER_REPORT = 45, /* Symbol error rate counter report */
|
||||
DIAG_CMD_TEST = 46, /* Run a specified test */
|
||||
DIAG_CMD_GET_DIPSW = 47, /* Retreive the current DIP switch setting */
|
||||
DIAG_CMD_SET_DIPSW = 48, /* Write new DIP switch setting */
|
||||
DIAG_CMD_VOC_PCM_LB = 49, /* Start/Stop Vocoder PCM loopback */
|
||||
DIAG_CMD_VOC_PKT_LB = 50, /* Start/Stop Vocoder PKT loopback */
|
||||
DIAG_CMD_ORIG = 53, /* Originate a call */
|
||||
DIAG_CMD_END = 54, /* End a call */
|
||||
DIAG_CMD_SW_VERSION = 56, /* Get software version */
|
||||
DIAG_CMD_DLOAD = 58, /* Switch to downloader */
|
||||
DIAG_CMD_TMOB = 59, /* Test Mode Commands and FTM commands*/
|
||||
DIAG_CMD_STATE = 63, /* Current state of the phone */
|
||||
DIAG_CMD_PILOT_SETS = 64, /* Return all current sets of pilots */
|
||||
DIAG_CMD_SPC = 65, /* Send the Service Programming Code to unlock */
|
||||
DIAG_CMD_BAD_SPC_MODE = 66, /* Invalid NV read/write because SP is locked */
|
||||
DIAG_CMD_PARM_GET2 = 67, /* (obsolete) */
|
||||
DIAG_CMD_SERIAL_CHG = 68, /* Serial mode change */
|
||||
DIAG_CMD_PASSWORD = 70, /* Send password to unlock secure operations */
|
||||
DIAG_CMD_BAD_SEC_MODE = 71, /* Operation not allowed in this security state */
|
||||
DIAG_CMD_PRL_WRITE = 72, /* Write PRL */
|
||||
DIAG_CMD_PRL_READ = 73, /* Read PRL */
|
||||
DIAG_CMD_SUBSYS = 75, /* Subsystem commands */
|
||||
DIAG_CMD_FEATURE_QUERY = 81,
|
||||
DIAG_CMD_SMS_READ = 83, /* Read SMS message out of NV memory */
|
||||
DIAG_CMD_SMS_WRITE = 84, /* Write SMS message into NV memory */
|
||||
DIAG_CMD_SUP_FER = 85, /* Frame Error Rate info on multiple channels */
|
||||
DIAG_CMD_SUP_WALSH_CODES = 86, /* Supplemental channel walsh codes */
|
||||
DIAG_CMD_SET_MAX_SUP_CH = 87, /* Sets the maximum # supplemental channels */
|
||||
DIAG_CMD_PARM_GET_IS95B = 88, /* Get parameters including SUPP and MUX2 */
|
||||
DIAG_CMD_FS_OP = 89, /* Embedded File System (EFS) operations */
|
||||
DIAG_CMD_AKEY_VERIFY = 90, /* AKEY Verification */
|
||||
DIAG_CMD_HS_BMP_SCREEN = 91, /* Handset Emulation -- Bitmap screen */
|
||||
DIAG_CMD_CONFIG_COMM = 92, /* Configure communications */
|
||||
DIAG_CMD_EXT_LOGMASK = 93, /* Extended logmask for > 32 bits */
|
||||
DIAG_CMD_EVENT_REPORT = 96, /* Static Event reporting */
|
||||
DIAG_CMD_STREAMING_CONFIG = 97, /* Load balancing etc */
|
||||
DIAG_CMD_PARM_RETRIEVE = 98, /* Parameter retrieval */
|
||||
DIAG_CMD_STATUS_SNAPSHOT = 99, /* Status snapshot */
|
||||
DIAG_CMD_RPC = 100, /* Used for RPC */
|
||||
DIAG_CMD_GET_PROPERTY = 101,
|
||||
DIAG_CMD_PUT_PROPERTY = 102,
|
||||
DIAG_CMD_GET_GUID = 103, /* GUID requests */
|
||||
DIAG_CMD_USER_CMD = 104, /* User callbacks */
|
||||
DIAG_CMD_GET_PERM_PROPERTY = 105,
|
||||
DIAG_CMD_PUT_PERM_PROPERTY = 106,
|
||||
DIAG_CMD_PERM_USER_CMD = 107, /* Permanent user callbacks */
|
||||
DIAG_CMD_GPS_SESS_CTRL = 108, /* GPS session control */
|
||||
DIAG_CMD_GPS_GRID = 109, /* GPS search grid */
|
||||
DIAG_CMD_GPS_STATISTICS = 110,
|
||||
DIAG_CMD_TUNNEL = 111, /* Tunneling command code */
|
||||
DIAG_CMD_RAM_RW = 112, /* Calibration RAM control using DM */
|
||||
DIAG_CMD_CPU_RW = 113, /* Calibration CPU control using DM */
|
||||
DIAG_CMD_SET_FTM_TEST_MODE = 114, /* Field (or Factory?) Test Mode */
|
||||
};
|
||||
|
||||
/* Subsystem IDs used with DIAG_CMD_SUBSYS; these often obsolete many of
|
||||
* the original DM commands.
|
||||
*/
|
||||
enum {
|
||||
DIAG_SUBSYS_HDR = 5, /* High Data Rate (ie, EVDO) */
|
||||
DIAG_SUBSYS_GPS = 13,
|
||||
DIAG_SUBSYS_SMS = 14,
|
||||
DIAG_SUBSYS_CM = 15, /* Call manager */
|
||||
DIAG_SUBSYS_NW_CONTROL_6500 = 50, /* for Novatel Wireless MSM6500-based devices */
|
||||
DIAG_SUBSYS_NW_CONTROL_6800 = 250 /* for Novatel Wireless MSM6800-based devices */
|
||||
};
|
||||
|
||||
/* HDR subsystem command codes */
|
||||
enum {
|
||||
DIAG_SUBSYS_HDR_STATE_INFO = 8, /* Gets EVDO state */
|
||||
};
|
||||
|
||||
enum {
|
||||
DIAG_SUBSYS_CM_STATE_INFO = 0, /* Gets Call Manager state */
|
||||
};
|
||||
|
||||
/* NW_CONTROL subsystem command codes (only for Novatel Wireless devices) */
|
||||
enum {
|
||||
DIAG_SUBSYS_NW_CONTROL_AT_REQUEST = 3, /* AT commands via diag */
|
||||
DIAG_SUBSYS_NW_CONTROL_AT_RESPONSE = 4,
|
||||
DIAG_SUBSYS_NW_CONTROL_MODEM_STATUS = 7, /* Modem status */
|
||||
DIAG_SUBSYS_NW_CONTROL_ERI = 8, /* Extended Roaming Indicator */
|
||||
DIAG_SUBSYS_NW_CONTROL_PRL = 12,
|
||||
};
|
||||
|
||||
enum {
|
||||
DIAG_SUBSYS_NW_CONTROL_MODEM_STATUS_CDMA = 7,
|
||||
DIAG_SUBSYS_NW_CONTROL_MODEM_STATUS_WCDMA = 20,
|
||||
};
|
||||
|
||||
/* Generic DM command header */
|
||||
struct DMCmdHeader {
|
||||
guint8 code;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct DMCmdHeader DMCmdHeader;
|
||||
|
||||
/* DIAG_CMD_SUBSYS */
|
||||
struct DMCmdSubsysHeader {
|
||||
guint8 code;
|
||||
guint8 subsys_id;
|
||||
guint16 subsys_cmd;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct DMCmdSubsysHeader DMCmdSubsysHeader;
|
||||
|
||||
/* DIAG_CMD_NV_READ / DIAG_CMD_NV_WRITE */
|
||||
struct DMCmdNVReadWrite {
|
||||
guint8 code;
|
||||
guint16 nv_item;
|
||||
guint8 data[128];
|
||||
guint16 status;
|
||||
} __attribute__ ((packed));
|
||||
typedef struct DMCmdNVReadWrite DMCmdNVReadWrite;
|
||||
|
||||
/* DIAG_CMD_VERSION_INFO */
|
||||
struct DMCmdVersionInfoRsp {
|
||||
guint8 code;
|
||||
char comp_date[11];
|
||||
char comp_time[8];
|
||||
char rel_date[11];
|
||||
char rel_time[8];
|
||||
char model[8];
|
||||
guint8 _unknown[8];
|
||||
} __attribute__ ((packed));
|
||||
typedef struct DMCmdVersionInfoRsp DMCmdVersionInfoRsp;
|
||||
|
||||
#endif /* LIBQCDM_DM_COMMANDS_H */
|
||||
|
82
libqcdm/src/error.c
Normal file
82
libqcdm/src/error.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
|
||||
|
||||
GQuark
|
||||
qcdm_serial_error_quark (void)
|
||||
{
|
||||
static GQuark ret = 0;
|
||||
|
||||
if (ret == 0)
|
||||
ret = g_quark_from_static_string ("qcdm-serial-error");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GType
|
||||
qcdm_serial_error_get_type (void)
|
||||
{
|
||||
static GType etype = 0;
|
||||
|
||||
if (etype == 0) {
|
||||
static const GEnumValue values[] = {
|
||||
ENUM_ENTRY (QCDM_SERIAL_CONFIG_FAILED, "SerialConfigFailed"),
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
etype = g_enum_register_static ("QcdmSerialError", values);
|
||||
}
|
||||
|
||||
return etype;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
|
||||
GQuark
|
||||
qcdm_command_error_quark (void)
|
||||
{
|
||||
static GQuark ret = 0;
|
||||
|
||||
if (ret == 0)
|
||||
ret = g_quark_from_static_string ("qcdm-command-error");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GType
|
||||
qcdm_command_error_get_type (void)
|
||||
{
|
||||
static GType etype = 0;
|
||||
|
||||
if (etype == 0) {
|
||||
static const GEnumValue values[] = {
|
||||
ENUM_ENTRY (QCDM_COMMAND_MALFORMED_RESPONSE, "QcdmCommandMalformedResponse"),
|
||||
ENUM_ENTRY (QCDM_COMMAND_UNEXPECTED, "QcdmCommandUnexpected"),
|
||||
ENUM_ENTRY (QCDM_COMMAND_BAD_LENGTH, "QcdmCommandBadLength"),
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
etype = g_enum_register_static ("QcdmCommandError", values);
|
||||
}
|
||||
|
||||
return etype;
|
||||
}
|
||||
|
||||
|
48
libqcdm/src/error.h
Normal file
48
libqcdm/src/error.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBQCDM_ERROR_H
|
||||
#define LIBQCDM_ERROR_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
enum {
|
||||
QCDM_SERIAL_CONFIG_FAILED = 0,
|
||||
};
|
||||
|
||||
#define QCDM_SERIAL_ERROR (qcdm_serial_error_quark ())
|
||||
#define QCDM_TYPE_SERIAL_ERROR (qcdm_serial_error_get_type ())
|
||||
|
||||
GQuark qcdm_serial_error_quark (void);
|
||||
GType qcdm_serial_error_get_type (void);
|
||||
|
||||
|
||||
enum {
|
||||
QCDM_COMMAND_MALFORMED_RESPONSE = 0,
|
||||
QCDM_COMMAND_UNEXPECTED = 1,
|
||||
QCDM_COMMAND_BAD_LENGTH = 2,
|
||||
};
|
||||
|
||||
#define QCDM_COMMAND_ERROR (qcdm_command_error_quark ())
|
||||
#define QCDM_TYPE_COMMAND_ERROR (qcdm_command_error_get_type ())
|
||||
|
||||
GQuark qcdm_command_error_quark (void);
|
||||
GType qcdm_command_error_get_type (void);
|
||||
|
||||
#endif /* LIBQCDM_ERROR_H */
|
||||
|
41
libqcdm/src/result-private.h
Normal file
41
libqcdm/src/result-private.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBQCDM_RESULT_PRIVATE_H
|
||||
#define LIBQCDM_RESULT_PRIVATE_H
|
||||
|
||||
#include <glib.h>
|
||||
#include "result.h"
|
||||
|
||||
QCDMResult *qcdm_result_new (void);
|
||||
|
||||
/* For these functions, 'key' *must* be a constant, not allocated and freed */
|
||||
|
||||
void qcdm_result_add_string (QCDMResult *result,
|
||||
const char *key,
|
||||
const char *str);
|
||||
|
||||
void qcdm_result_add_uint8 (QCDMResult *result,
|
||||
const char *key,
|
||||
guint8 num);
|
||||
|
||||
void qcdm_result_add_uint32 (QCDMResult *result,
|
||||
const char *key,
|
||||
guint32 num);
|
||||
|
||||
#endif /* LIBQCDM_RESULT_PRIVATE_H */
|
||||
|
204
libqcdm/src/result.c
Normal file
204
libqcdm/src/result.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "result.h"
|
||||
#include "result-private.h"
|
||||
#include "error.h"
|
||||
|
||||
struct QCDMResult {
|
||||
guint32 refcount;
|
||||
GHashTable *hash;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
gvalue_destroy (gpointer data)
|
||||
{
|
||||
GValue *value = (GValue *) data;
|
||||
|
||||
g_value_unset (value);
|
||||
g_slice_free (GValue, value);
|
||||
}
|
||||
|
||||
QCDMResult *
|
||||
qcdm_result_new (void)
|
||||
{
|
||||
QCDMResult *result;
|
||||
|
||||
result = g_malloc0 (sizeof (QCDMResult));
|
||||
result->hash = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL, gvalue_destroy);
|
||||
result->refcount = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
QCDMResult *
|
||||
qcdm_result_ref (QCDMResult *result)
|
||||
{
|
||||
g_return_val_if_fail (result != NULL, NULL);
|
||||
g_return_val_if_fail (result->refcount > 0, NULL);
|
||||
|
||||
result->refcount++;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
qcdm_result_unref (QCDMResult *result)
|
||||
{
|
||||
g_return_if_fail (result != NULL);
|
||||
g_return_if_fail (result->refcount == 0);
|
||||
|
||||
result->refcount--;
|
||||
if (result->refcount == 0) {
|
||||
g_hash_table_destroy (result->hash);
|
||||
memset (result, 0, sizeof (QCDMResult));
|
||||
g_free (result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
qcdm_result_add_string (QCDMResult *result,
|
||||
const char *key,
|
||||
const char *str)
|
||||
{
|
||||
GValue *val;
|
||||
|
||||
g_return_if_fail (result != NULL);
|
||||
g_return_if_fail (result->refcount > 0);
|
||||
g_return_if_fail (key != NULL);
|
||||
g_return_if_fail (str != NULL);
|
||||
|
||||
val = g_slice_new0 (GValue);
|
||||
g_value_init (val, G_TYPE_STRING);
|
||||
g_value_set_string (val, str);
|
||||
|
||||
g_hash_table_insert (result->hash, (gpointer) key, val);
|
||||
}
|
||||
|
||||
gboolean
|
||||
qcdm_result_get_string (QCDMResult *result,
|
||||
const char *key,
|
||||
const char **out_val)
|
||||
{
|
||||
GValue *val;
|
||||
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
g_return_val_if_fail (result->refcount > 0, FALSE);
|
||||
g_return_val_if_fail (key != NULL, FALSE);
|
||||
g_return_val_if_fail (out_val != NULL, FALSE);
|
||||
g_return_val_if_fail (*out_val == NULL, FALSE);
|
||||
|
||||
val = g_hash_table_lookup (result->hash, key);
|
||||
if (!val)
|
||||
return FALSE;
|
||||
|
||||
g_warn_if_fail (G_VALUE_HOLDS_STRING (val));
|
||||
if (!G_VALUE_HOLDS_STRING (val))
|
||||
return FALSE;
|
||||
|
||||
*out_val = g_value_get_string (val);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
qcdm_result_add_uint8 (QCDMResult *result,
|
||||
const char *key,
|
||||
guint8 num)
|
||||
{
|
||||
GValue *val;
|
||||
|
||||
g_return_if_fail (result != NULL);
|
||||
g_return_if_fail (result->refcount > 0);
|
||||
g_return_if_fail (key != NULL);
|
||||
|
||||
val = g_slice_new0 (GValue);
|
||||
g_value_init (val, G_TYPE_UCHAR);
|
||||
g_value_set_uchar (val, (unsigned char) num);
|
||||
|
||||
g_hash_table_insert (result->hash, (gpointer) key, val);
|
||||
}
|
||||
|
||||
gboolean
|
||||
qcdm_result_get_uint8 (QCDMResult *result,
|
||||
const char *key,
|
||||
guint8 *out_val)
|
||||
{
|
||||
GValue *val;
|
||||
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
g_return_val_if_fail (result->refcount > 0, FALSE);
|
||||
g_return_val_if_fail (key != NULL, FALSE);
|
||||
g_return_val_if_fail (out_val != NULL, FALSE);
|
||||
|
||||
val = g_hash_table_lookup (result->hash, key);
|
||||
if (!val)
|
||||
return FALSE;
|
||||
|
||||
g_warn_if_fail (G_VALUE_HOLDS_CHAR (val));
|
||||
if (!G_VALUE_HOLDS_CHAR (val))
|
||||
return FALSE;
|
||||
|
||||
*out_val = (guint8) g_value_get_char (val);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
qcdm_result_add_uint32 (QCDMResult *result,
|
||||
const char *key,
|
||||
guint32 num)
|
||||
{
|
||||
GValue *val;
|
||||
|
||||
g_return_if_fail (result != NULL);
|
||||
g_return_if_fail (result->refcount > 0);
|
||||
g_return_if_fail (key != NULL);
|
||||
|
||||
val = g_slice_new0 (GValue);
|
||||
g_value_init (val, G_TYPE_UINT);
|
||||
g_value_set_uint (val, num);
|
||||
|
||||
g_hash_table_insert (result->hash, (gpointer) key, val);
|
||||
}
|
||||
|
||||
gboolean
|
||||
qcdm_result_get_uint32 (QCDMResult *result,
|
||||
const char *key,
|
||||
guint32 *out_val)
|
||||
{
|
||||
GValue *val;
|
||||
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
g_return_val_if_fail (result->refcount > 0, FALSE);
|
||||
g_return_val_if_fail (key != NULL, FALSE);
|
||||
g_return_val_if_fail (out_val != NULL, FALSE);
|
||||
|
||||
val = g_hash_table_lookup (result->hash, key);
|
||||
if (!val)
|
||||
return FALSE;
|
||||
|
||||
g_warn_if_fail (G_VALUE_HOLDS_UINT (val));
|
||||
if (!G_VALUE_HOLDS_UINT (val))
|
||||
return FALSE;
|
||||
|
||||
*out_val = (guint32) g_value_get_uint (val);
|
||||
return TRUE;
|
||||
}
|
||||
|
42
libqcdm/src/result.h
Normal file
42
libqcdm/src/result.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBQCDM_RESULT_H
|
||||
#define LIBQCDM_RESULT_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct QCDMResult QCDMResult;
|
||||
|
||||
gboolean qcdm_result_get_string (QCDMResult *result,
|
||||
const char *key,
|
||||
const char **out_val);
|
||||
|
||||
gboolean qcdm_result_get_uint8 (QCDMResult *result,
|
||||
const char *key,
|
||||
guint8 *out_val);
|
||||
|
||||
gboolean qcdm_result_get_uint32 (QCDMResult *result,
|
||||
const char *key,
|
||||
guint32 *out_val);
|
||||
|
||||
QCDMResult *qcdm_result_ref (QCDMResult *result);
|
||||
|
||||
void qcdm_result_unref (QCDMResult *result);
|
||||
|
||||
#endif /* LIBQCDM_RESULT_H */
|
||||
|
@@ -78,7 +78,6 @@ crc16 (const char *buffer, gsize len)
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
#define DIAG_CONTROL_CHAR 0x7E
|
||||
#define DIAG_ESC_CHAR 0x7D /* Escape sequence 1st character value */
|
||||
#define DIAG_ESC_MASK 0x20 /* Escape sequence complement value */
|
||||
|
||||
@@ -167,3 +166,29 @@ dm_unescape (const char *inbuf,
|
||||
return outsize;
|
||||
}
|
||||
|
||||
gsize
|
||||
dm_prepare_buffer (char *inbuf,
|
||||
gsize cmd_len,
|
||||
gsize inbuf_len,
|
||||
char *outbuf,
|
||||
gsize outbuf_len)
|
||||
{
|
||||
guint16 crc;
|
||||
gsize escaped_len;
|
||||
|
||||
g_return_val_if_fail (inbuf != NULL, 0);
|
||||
g_return_val_if_fail (cmd_len >= 1, 0);
|
||||
g_return_val_if_fail (inbuf_len >= cmd_len + 2, 0); /* space for CRC */
|
||||
g_return_val_if_fail (outbuf != NULL, 0);
|
||||
|
||||
crc = GUINT16_TO_LE (crc16 (inbuf, cmd_len));
|
||||
inbuf[cmd_len++] = crc & 0xFF;
|
||||
inbuf[cmd_len++] = (crc >> 8) & 0xFF;
|
||||
|
||||
escaped_len = dm_escape (inbuf, cmd_len, outbuf, outbuf_len);
|
||||
g_return_val_if_fail (outbuf_len > escaped_len, 0);
|
||||
outbuf[escaped_len++] = DIAG_CONTROL_CHAR;
|
||||
|
||||
return escaped_len;
|
||||
}
|
||||
|
||||
|
@@ -20,6 +20,9 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define DIAG_CONTROL_CHAR 0x7E
|
||||
#define DIAG_TRAILER_LEN 3
|
||||
|
||||
guint16 crc16 (const char *buffer, gsize len);
|
||||
|
||||
gsize dm_escape (const char *inbuf,
|
||||
@@ -33,5 +36,11 @@ gsize dm_unescape (const char *inbuf,
|
||||
gsize outbuf_len,
|
||||
gboolean *escaping);
|
||||
|
||||
gsize dm_prepare_buffer (char *inbuf,
|
||||
gsize cmd_len,
|
||||
gsize inbuf_len,
|
||||
char *outbuf,
|
||||
gsize outbuf_len);
|
||||
|
||||
#endif /* UTILS_H */
|
||||
|
||||
|
@@ -8,6 +8,8 @@ test_qcdm_SOURCES = \
|
||||
test-qcdm-crc.h \
|
||||
test-qcdm-escaping.c \
|
||||
test-qcdm-escaping.h \
|
||||
test-qcdm-com.c \
|
||||
test-qcdm-com.h \
|
||||
test-qcdm.c
|
||||
|
||||
test_qcdm_CPPFLAGS = \
|
||||
|
241
libqcdm/tests/test-qcdm-com.c
Normal file
241
libqcdm/tests/test-qcdm-com.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test-qcdm-com.h"
|
||||
#include "com.h"
|
||||
#include "utils.h"
|
||||
#include "result.h"
|
||||
#include "commands.h"
|
||||
|
||||
typedef struct {
|
||||
char *port;
|
||||
int fd;
|
||||
struct termios old_t;
|
||||
gboolean debug;
|
||||
} TestComData;
|
||||
|
||||
gpointer
|
||||
test_com_setup (const char *port)
|
||||
{
|
||||
TestComData *d;
|
||||
int ret;
|
||||
|
||||
d = g_malloc0 (sizeof (TestComData));
|
||||
g_assert (d);
|
||||
|
||||
if (getenv ("SERIAL_DEBUG"))
|
||||
d->debug = TRUE;
|
||||
|
||||
errno = 0;
|
||||
d->fd = open (port, O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
|
||||
if (d->fd < 0)
|
||||
g_warning ("%s: open failed: (%d) %s", port, errno, strerror (errno));
|
||||
g_assert (d->fd >= 0);
|
||||
|
||||
ret = ioctl (d->fd, TIOCEXCL);
|
||||
if (ret) {
|
||||
g_warning ("%s: lock failed: (%d) %s", port, errno, strerror (errno));
|
||||
close (d->fd);
|
||||
d->fd = -1;
|
||||
}
|
||||
g_assert (ret == 0);
|
||||
|
||||
ret = ioctl (d->fd, TCGETA, &d->old_t);
|
||||
if (ret) {
|
||||
g_warning ("%s: old termios failed: (%d) %s", port, errno, strerror (errno));
|
||||
close (d->fd);
|
||||
d->fd = -1;
|
||||
}
|
||||
g_assert (ret == 0);
|
||||
|
||||
d->port = g_strdup (port);
|
||||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
test_com_teardown (gpointer user_data)
|
||||
{
|
||||
TestComData *d = user_data;
|
||||
|
||||
g_assert (d);
|
||||
|
||||
g_free (d->port);
|
||||
close (d->fd);
|
||||
g_free (d);
|
||||
}
|
||||
|
||||
static void
|
||||
print_buf (const char *detail, const char *buf, gsize len)
|
||||
{
|
||||
int i = 0;
|
||||
gboolean newline = FALSE;
|
||||
|
||||
g_print ("%s (%zu) ", detail, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
g_print ("0x%02x ", buf[i] & 0xFF);
|
||||
if (((i + 1) % 12) == 0) {
|
||||
g_print ("\n");
|
||||
newline = TRUE;
|
||||
} else
|
||||
newline = FALSE;
|
||||
}
|
||||
|
||||
if (!newline)
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
send_command (TestComData *d, char *buf, gsize len)
|
||||
{
|
||||
int status;
|
||||
int eagain_count = 1000;
|
||||
gsize i = 0;
|
||||
|
||||
if (d->debug)
|
||||
print_buf (">>>", buf, len);
|
||||
|
||||
while (i < len) {
|
||||
errno = 0;
|
||||
status = write (d->fd, &buf[i], 1);
|
||||
if (status < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
eagain_count--;
|
||||
if (eagain_count <= 0)
|
||||
return FALSE;
|
||||
} else
|
||||
g_assert (errno == 0);
|
||||
} else
|
||||
i++;
|
||||
|
||||
usleep (1000);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gsize
|
||||
wait_reply (TestComData *d, char *buf, gsize len)
|
||||
{
|
||||
fd_set in;
|
||||
int result;
|
||||
struct timeval timeout = { 1, 0 };
|
||||
char readbuf[1024];
|
||||
ssize_t bytes_read;
|
||||
char *p = &readbuf[0];
|
||||
int total = 0, retries = 0;
|
||||
gboolean escaping = FALSE;
|
||||
|
||||
FD_ZERO (&in);
|
||||
FD_SET (d->fd, &in);
|
||||
result = select (d->fd + 1, &in, NULL, NULL, &timeout);
|
||||
if (result != 1 || !FD_ISSET (d->fd, &in))
|
||||
return 0;
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
bytes_read = read (d->fd, p, 1);
|
||||
if ((bytes_read == 0) || (errno == EAGAIN)) {
|
||||
/* Haven't gotten the async control char yet */
|
||||
if (retries > 20)
|
||||
return 0; /* 2 seconds, give up */
|
||||
|
||||
/* Otherwise wait a bit and try again */
|
||||
usleep (100000);
|
||||
retries++;
|
||||
continue;
|
||||
} else if (bytes_read == 1) {
|
||||
/* Check for the async control char */
|
||||
if (*p++ == DIAG_CONTROL_CHAR)
|
||||
break;
|
||||
total++;
|
||||
} else {
|
||||
/* Some error occurred */
|
||||
return 0;
|
||||
}
|
||||
} while (total <= sizeof (readbuf));
|
||||
|
||||
if (d->debug)
|
||||
print_buf ("<<<", readbuf, total);
|
||||
|
||||
return dm_unescape (readbuf, total, buf, len, &escaping);
|
||||
}
|
||||
|
||||
void
|
||||
test_com (void *f, void *data)
|
||||
{
|
||||
TestComData *d = data;
|
||||
gboolean success;
|
||||
GError *error = NULL;
|
||||
char buf[100];
|
||||
const char *str;
|
||||
gint len;
|
||||
QCDMResult *result;
|
||||
gsize reply_len;
|
||||
|
||||
success = qcdm_port_setup (d->fd, &error);
|
||||
if (!success) {
|
||||
g_warning ("%s: error setting up port: (%d) %s",
|
||||
d->port,
|
||||
error ? error->code : -1,
|
||||
error && error->message ? error->message : "(unknown)");
|
||||
}
|
||||
g_assert (success);
|
||||
|
||||
len = qcdm_cmd_version_info_new (buf, sizeof (buf), NULL);
|
||||
g_assert (len == 4);
|
||||
|
||||
/* Send the command */
|
||||
success = send_command (d, buf, len);
|
||||
g_assert (success);
|
||||
|
||||
/* Get a response */
|
||||
reply_len = wait_reply (d, buf, sizeof (buf));
|
||||
|
||||
/* Parse the response into a result structure */
|
||||
result = qcdm_cmd_version_info_result (buf, reply_len, &error);
|
||||
g_assert (result);
|
||||
|
||||
str = NULL;
|
||||
qcdm_result_get_string (result, QCDM_CMD_VERSION_INFO_ITEM_COMP_DATE, &str);
|
||||
g_message ("%s: Compiled Date: %s", __func__, str);
|
||||
|
||||
str = NULL;
|
||||
qcdm_result_get_string (result, QCDM_CMD_VERSION_INFO_ITEM_COMP_TIME, &str);
|
||||
g_message ("%s: Compiled Time: %s", __func__, str);
|
||||
|
||||
str = NULL;
|
||||
qcdm_result_get_string (result, QCDM_CMD_VERSION_INFO_ITEM_RELEASE_DATE, &str);
|
||||
g_message ("%s: Release Date: %s", __func__, str);
|
||||
|
||||
str = NULL;
|
||||
qcdm_result_get_string (result, QCDM_CMD_VERSION_INFO_ITEM_RELEASE_TIME, &str);
|
||||
g_message ("%s: Release Time: %s", __func__, str);
|
||||
|
||||
str = NULL;
|
||||
qcdm_result_get_string (result, QCDM_CMD_VERSION_INFO_ITEM_MODEL, &str);
|
||||
g_message ("%s: Model: %s", __func__, str);
|
||||
}
|
||||
|
27
libqcdm/tests/test-qcdm-com.h
Normal file
27
libqcdm/tests/test-qcdm-com.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TEST_QCDM_COM_H
|
||||
#define TEST_QCDM_COM_H
|
||||
|
||||
gpointer test_com_setup (const char *port);
|
||||
void test_com_teardown (gpointer d);
|
||||
|
||||
void test_com (void *f, void *data);
|
||||
|
||||
#endif /* TEST_QCDM_COM_H */
|
||||
|
@@ -20,17 +20,60 @@
|
||||
|
||||
#include "test-qcdm-crc.h"
|
||||
#include "test-qcdm-escaping.h"
|
||||
#include "test-qcdm-com.h"
|
||||
|
||||
typedef struct {
|
||||
gpointer com_data;
|
||||
} TestData;
|
||||
|
||||
typedef void (*TCFunc)(void);
|
||||
|
||||
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
|
||||
|
||||
static TestData *
|
||||
test_data_new (const char *port)
|
||||
{
|
||||
TestData *d;
|
||||
|
||||
d = g_malloc0 (sizeof (TestData));
|
||||
g_assert (d);
|
||||
|
||||
if (port)
|
||||
d->com_data = test_com_setup (port);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static void
|
||||
test_data_free (TestData *d)
|
||||
{
|
||||
if (d->com_data)
|
||||
test_com_teardown (d->com_data);
|
||||
|
||||
g_free (d);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
GTestSuite *suite;
|
||||
TestData *data;
|
||||
int i;
|
||||
const char *port = NULL;
|
||||
gint result;
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
/* See if we got passed a serial port for live testing */
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!strcmp (argv[i], "--port")) {
|
||||
/* Make sure there's actually a port in the next arg */
|
||||
g_assert (argc > i + 1);
|
||||
port = argv[++i];
|
||||
}
|
||||
}
|
||||
|
||||
data = test_data_new (port);
|
||||
|
||||
suite = g_test_get_root ();
|
||||
|
||||
g_test_suite_add (suite, TESTCASE (test_crc16_1, NULL));
|
||||
@@ -39,6 +82,14 @@ int main (int argc, char **argv)
|
||||
g_test_suite_add (suite, TESTCASE (test_escape2, NULL));
|
||||
g_test_suite_add (suite, TESTCASE (test_escape_unescape, NULL));
|
||||
|
||||
return g_test_run ();
|
||||
/* Live tests */
|
||||
if (port)
|
||||
g_test_suite_add (suite, TESTCASE (test_com, data->com_data));
|
||||
|
||||
result = g_test_run ();
|
||||
|
||||
test_data_free (data);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user