diff options
author | Dan Williams <dcbw@redhat.com> | 2011-11-11 12:20:51 -0600 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2011-11-11 12:21:41 -0600 |
commit | ae3f1cd578e59245a6bff5cfd19f64f0c47f5de9 (patch) | |
tree | 5db2e66c1688643a58567bc97a58048b798b9c20 | |
parent | 83c905837693f095d9e7c1bf9ac56d8290510f45 (diff) |
libwmc: add testcases that talk to the device
-rw-r--r-- | libwmc/src/commands.c | 70 | ||||
-rw-r--r-- | libwmc/src/commands.h | 5 | ||||
-rw-r--r-- | libwmc/src/protocol.h | 17 | ||||
-rw-r--r-- | libwmc/src/utils.c | 79 | ||||
-rw-r--r-- | libwmc/src/utils.h | 26 | ||||
-rw-r--r-- | libwmc/tests/test-wmc-com.c | 104 | ||||
-rw-r--r-- | libwmc/tests/test-wmc-com.h | 6 | ||||
-rw-r--r-- | libwmc/tests/test-wmc-utils.c | 4 | ||||
-rw-r--r-- | libwmc/tests/test-wmc.c | 12 |
9 files changed, 293 insertions, 30 deletions
diff --git a/libwmc/src/commands.c b/libwmc/src/commands.c index 08bfd4da..cda4a5be 100644 --- a/libwmc/src/commands.c +++ b/libwmc/src/commands.c @@ -27,16 +27,22 @@ /**********************************************************************/ static int -check_command (const char *buf, gsize len, guint8 cmd, gsize min_len) +check_command (const char *buf, gsize len, u_int8_t cmd, size_t min_len) { if (len < 1) { wmc_err (0, "Zero-length response"); return -WMC_ERROR_RESPONSE_BAD_LENGTH; } - if (buf[0] != cmd) { - wmc_err (0, "Unexpected WMC command response (expected %d, got %d)", - cmd, buf[0]); + if ((u_int8_t) buf[0] != WMC_CMD_MARKER) { + wmc_err (0, "Missing WMC command marker (expected 0x%02X, got 0x%02X)", + WMC_CMD_MARKER, (u_int8_t) buf[0]); + return -WMC_ERROR_RESPONSE_UNEXPECTED; + } + + if ((u_int8_t) buf[1] != cmd) { + wmc_err (0, "Unexpected WMC command response (expected 0x%02X, got 0x%02X)", + (u_int8_t) cmd, (u_int8_t) buf[1]); return -WMC_ERROR_RESPONSE_UNEXPECTED; } @@ -51,6 +57,61 @@ check_command (const char *buf, gsize len, guint8 cmd, gsize min_len) /**********************************************************************/ +/** + * wmc_cmd_init_new: + * @buf: buffer in which to store constructed command + * @buflen: size of @buf + * @wmc2: if %TRUE add additional data that later-model devices (UML290) want + * + * Returns: size of the constructed command on success, or 0 on failure + */ +size_t +wmc_cmd_init_new (char *buf, size_t buflen, int wmc2) +{ + wmc_return_val_if_fail (buf != NULL, 0); + + if (wmc2) { + WmcCmdInit2 *cmd = (WmcCmdInit2 *) buf; + const char data[] = { 0xda, 0x07, 0x0c, 0x00, 0x1e, 0x00, 0x09, 0x00, 0x39, + 0x00, 0x18, 0x00, 0x04, 0x00 }; + + wmc_return_val_if_fail (buflen >= sizeof (*cmd), 0); + + memset (cmd, 0, sizeof (*cmd)); + cmd->hdr.marker = WMC_CMD_MARKER; + cmd->hdr.cmd = WMC_CMD_INIT; + memcpy (cmd->_unknown1, data, sizeof (data)); + return sizeof (*cmd); + } else { + WmcCmdHeader *cmd = (WmcCmdHeader *) buf; + + wmc_return_val_if_fail (buflen >= sizeof (*cmd), 0); + + memset (cmd, 0, sizeof (*cmd)); + cmd->marker = WMC_CMD_MARKER; + cmd->cmd = WMC_CMD_INIT; + return sizeof (*cmd); + } +} + +WmcResult * +wmc_cmd_init_result (const char *buf, gsize buflen, int wmc2) +{ + g_return_val_if_fail (buf != NULL, NULL); + + if (wmc2) { + if (check_command (buf, buflen, WMC_CMD_INIT, sizeof (WmcCmdInit2Rsp)) < 0) + return NULL; + } else { + if (check_command (buf, buflen, WMC_CMD_INIT, sizeof (WmcCmdHeader)) < 0) + return NULL; + } + + return wmc_result_new (); +} + +/**********************************************************************/ + size_t wmc_cmd_device_info_new (char *buf, size_t buflen) { @@ -60,6 +121,7 @@ wmc_cmd_device_info_new (char *buf, size_t buflen) wmc_return_val_if_fail (buflen >= sizeof (*cmd), 0); memset (cmd, 0, sizeof (*cmd)); + cmd->marker = WMC_CMD_MARKER; cmd->cmd = WMC_CMD_DEVICE_INFO; return sizeof (*cmd); } diff --git a/libwmc/src/commands.h b/libwmc/src/commands.h index dba839b5..60ecdac0 100644 --- a/libwmc/src/commands.h +++ b/libwmc/src/commands.h @@ -24,6 +24,11 @@ /* Generic enums */ +/**********************************************************************/ + +size_t wmc_cmd_init_new (char *buf, size_t buflen, int wmc2); + +WmcResult * wmc_cmd_init_result (const char *buf, size_t len, int wmc2); /**********************************************************************/ diff --git a/libwmc/src/protocol.h b/libwmc/src/protocol.h index 7bc751ee..b09322dd 100644 --- a/libwmc/src/protocol.h +++ b/libwmc/src/protocol.h @@ -18,10 +18,13 @@ #ifndef LIBWMC_PROTOCOL_H #define LIBWMC_PROTOCOL_H +#define WMC_CMD_MARKER ((u_int8_t) 0xC8) + enum { WMC_CMD_DEVICE_INFO = 0x06, WMC_CMD_IP_INFO = 0x0A, WMC_CMD_STATUS = 0x0B, + WMC_CMD_INIT = 0x0D, WMC_CMD_EPS_BEARER_INFO = 0x4D, }; @@ -33,6 +36,20 @@ struct WmcCmdHeader { } __attribute__ ((packed)); typedef struct WmcCmdHeader WmcCmdHeader; +/* Used on newer devices like the UML290 */ +struct WmcCmdInit2 { + WmcCmdHeader hdr; + u_int8_t _unknown1[14]; +} __attribute__ ((packed)); +typedef struct WmcCmdInit2 WmcCmdInit2; + +struct WmcCmdInit2Rsp { + WmcCmdHeader hdr; + u_int8_t _unknown1[4]; +} __attribute__ ((packed)); +typedef struct WmcCmdInit2Rsp WmcCmdInit2Rsp; + + struct WmcCmdDeviceInfoRsp { WmcCmdHeader hdr; u_int8_t _unknown1[27]; diff --git a/libwmc/src/utils.c b/libwmc/src/utils.c index 3c470330..ce3bb7af 100644 --- a/libwmc/src/utils.c +++ b/libwmc/src/utils.c @@ -236,7 +236,7 @@ hdlc_encapsulate_buffer (char *inbuf, * * Returns: size of the encapsulated data writted to @outbuf. */ -gsize +static gsize uml290_wmc_encapsulate (char *inbuf, gsize cmd_len, gsize inbuf_len, @@ -251,7 +251,7 @@ uml290_wmc_encapsulate (char *inbuf, g_return_val_if_fail (inbuf_len >= cmd_len + 2, 0); /* space for CRC */ g_return_val_if_fail (outbuf != NULL, 0); - estimated_out_len = inbuf_len + strlen (AT_WMC_PREFIX); + estimated_out_len = cmd_len + strlen (AT_WMC_PREFIX); estimated_out_len += 3; /* CRC + trailer */ estimated_out_len += cmd_len * 1.3; /* escaping */ g_return_val_if_fail (outbuf_len > estimated_out_len, 0); @@ -271,6 +271,40 @@ uml290_wmc_encapsulate (char *inbuf, } /** + * wmc_encapsulate: + * @inbuf: data buffer to encapsulate + * @cmd_len: size of the data contained in @inbuf + * @inbuf_len: total size of @inbuf itself (not just the data) + * @outbuf: buffer in which to put the encapsulated data + * @outbuf_len: total size of @outbuf + * @uml290: if %TRUE return buffer suitable for sending to UML290 devices + * + * Escapes and CRCs given data using HDLC-style mechanisms. + * + * Returns: size of the encapsulated data writted to @outbuf. + */ +gsize +wmc_encapsulate (char *inbuf, + gsize cmd_len, + gsize inbuf_len, + char *outbuf, + gsize outbuf_len, + gboolean uml290) +{ + 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 + 3, 0); /* space for CRC + trailer */ + g_return_val_if_fail (outbuf != NULL, 0); + + if (uml290) + return uml290_wmc_encapsulate (inbuf, cmd_len, inbuf_len, outbuf, outbuf_len); + + /* Otherwise do normal WMC */ + return hdlc_encapsulate_buffer (inbuf, cmd_len, inbuf_len, + 0, TRUE, FALSE, outbuf, outbuf_len); +} + +/** * hdlc_decapsulate_buffer: * @inbuf: buffer in which to look for an HDLC frame * @inbuf_len: length of valid data in @inbuf @@ -382,3 +416,44 @@ hdlc_decapsulate_buffer (const char *inbuf, return TRUE; } +/** + * wmc_decapsulate: + * @inbuf: buffer in which to look for an HDLC frame + * @inbuf_len: length of valid data in @inbuf + * @outbuf: buffer in which to put decapsulated data from the HDLC frame + * @outbuf_len: max size of @outbuf + * @out_decap_len: on success, size of the decapsulated data + * @out_used: on either success or failure, amount of data used; caller should + * discard this much data from @inbuf before the next call to this function + * @out_need_more: when TRUE, indicates that more data is required before + * a determination about a valid HDLC frame can be made; caller should add + * more data to @inbuf before calling this function again. + * @uml290: if %TRUE decapsulate response from UML290 devices + * + * Attempts to retrieve, unescape, and CRC-check an HDLC frame from the given + * buffer. + * + * Returns: FALSE on error (packet was invalid or malformed, or the CRC check + * failed, etc) and places number of bytes to discard from @inbuf in @out_used. + * When TRUE, either more data is required (in which case @out_need_more will + * be TRUE), or a data packet was successfully retrieved from @inbuf and the + * decapsulated packet of length @out_decap_len was placed into @outbuf. In + * all cases the caller should advance the buffer by the number of bytes + * returned in @out_used before calling this function again. + **/ +gboolean +wmc_decapsulate (const char *inbuf, + gsize inbuf_len, + char *outbuf, + gsize outbuf_len, + gsize *out_decap_len, + gsize *out_used, + gboolean *out_need_more, + gboolean uml290) +{ + return hdlc_decapsulate_buffer (inbuf, inbuf_len, + uml290, uml290 ? 0x3030 : 0, + outbuf, outbuf_len, + out_decap_len, out_used, out_need_more); +} + diff --git a/libwmc/src/utils.h b/libwmc/src/utils.h index 4a7ab302..2163784e 100644 --- a/libwmc/src/utils.h +++ b/libwmc/src/utils.h @@ -23,6 +23,8 @@ #define DIAG_CONTROL_CHAR 0x7E #define DIAG_TRAILER_LEN 3 +/* Utility and testcase functions */ + guint16 crc16 (const char *buffer, gsize len, guint16 seed); gsize hdlc_escape (const char *inbuf, @@ -46,12 +48,6 @@ gsize hdlc_encapsulate_buffer (char *inbuf, char *outbuf, gsize outbuf_len); -gsize uml290_wmc_encapsulate (char *inbuf, - gsize cmd_len, - gsize inbuf_len, - char *outbuf, - gsize outbuf_len); - gboolean hdlc_decapsulate_buffer (const char *inbuf, gsize inbuf_len, gboolean check_known_crc, @@ -62,5 +58,23 @@ gboolean hdlc_decapsulate_buffer (const char *inbuf, gsize *out_used, gboolean *out_need_more); +/* Functions for actual communication */ + +gsize wmc_encapsulate (char *inbuf, + gsize cmd_len, + gsize inbuf_len, + char *outbuf, + gsize outbuf_len, + gboolean uml290); + +gboolean wmc_decapsulate (const char *inbuf, + gsize inbuf_len, + char *outbuf, + gsize outbuf_len, + gsize *out_decap_len, + gsize *out_used, + gboolean *out_need_more, + gboolean uml290); + #endif /* UTILS_H */ diff --git a/libwmc/tests/test-wmc-com.c b/libwmc/tests/test-wmc-com.c index 643c0993..bf906ed6 100644 --- a/libwmc/tests/test-wmc-com.c +++ b/libwmc/tests/test-wmc-com.c @@ -28,6 +28,7 @@ #include "com.h" #include "utils.h" #include "errors.h" +#include "commands.h" /************************************************************/ @@ -40,7 +41,7 @@ typedef struct { } TestComData; gpointer -test_com_setup (const char *port, gboolean uml290) +test_com_setup (const char *port, gboolean uml290, gboolean debug) { TestComData *d; int ret; @@ -48,6 +49,7 @@ test_com_setup (const char *port, gboolean uml290) d = g_malloc0 (sizeof (TestComData)); g_assert (d); d->uml290 = uml290; + d->debug = debug; if (getenv ("SERIAL_DEBUG")) d->debug = TRUE; @@ -90,7 +92,6 @@ test_com_teardown (gpointer user_data) g_free (d); } -#if 0 static void print_buf (const char *detail, const char *buf, gsize len) { @@ -112,18 +113,29 @@ print_buf (const char *detail, const char *buf, gsize len) } static gboolean -send_command (TestComData *d, char *buf, gsize len) +send_command (TestComData *d, + char *inbuf, + gsize inbuf_len, + gsize cmd_len) { int status; int eagain_count = 1000; - gsize i = 0; + gsize i = 0, sendlen; + char sendbuf[600]; + + /* Encapsulate the data for the device */ + sendlen = wmc_encapsulate (inbuf, cmd_len, inbuf_len, sendbuf, sizeof (sendbuf), d->uml290); + if (sendlen <= 0) { + g_warning ("Failed to encapsulate WMC command"); + return FALSE; + } if (d->debug) - print_buf (">>>", buf, len); + print_buf (">>>", sendbuf, sendlen); - while (i < len) { + while (i < sendlen) { errno = 0; - status = write (d->fd, &buf[i], 1); + status = write (d->fd, &sendbuf[i], 1); if (status < 0) { if (errno == EAGAIN) { eagain_count--; @@ -175,9 +187,7 @@ wait_reply (TestComData *d, char *buf, gsize len) total++; decap_len = 0; - success = hdlc_decapsulate_buffer (readbuf, total, d->uml290, 0x3030, - buf, len, &decap_len, - &used, &more); + success = wmc_decapsulate (readbuf, total, buf, len, &decap_len, &used, &more, d->uml290); /* Discard used data */ if (used > 0) { @@ -202,7 +212,6 @@ wait_reply (TestComData *d, char *buf, gsize len) return decap_len; } -#endif void test_com_port_init (void *f, void *data) @@ -216,3 +225,76 @@ test_com_port_init (void *f, void *data) g_assert_cmpint (ret, ==, 0); } +void +test_com_init (void *f, void *data) +{ + TestComData *d = data; + gboolean success; + char buf[512]; + gint len; + WmcResult *result; + gsize reply_len; + + len = wmc_cmd_init_new (buf, sizeof (buf), d->uml290); + g_assert (len == 16); + + /* Send the command */ + success = send_command (d, buf, sizeof (buf), len); + g_assert (success); + + /* Get a response */ + reply_len = wait_reply (d, buf, sizeof (buf)); + + /* Parse the response into a result structure */ + result = wmc_cmd_init_result (buf, reply_len, d->uml290); + g_assert (result); + + wmc_result_unref (result); +} + +void +test_com_device_info (void *f, void *data) +{ + TestComData *d = data; + gboolean success; + char buf[1024]; + const char *str; + gint len; + WmcResult *result; + gsize reply_len; + + len = wmc_cmd_device_info_new (buf, sizeof (buf)); + g_assert (len == 2); + + /* Send the command */ + success = send_command (d, buf, sizeof (buf), len); + g_assert (success); + + /* Get a response */ + reply_len = wait_reply (d, buf, sizeof (buf)); + + /* Parse the response into a result structure */ + result = wmc_cmd_device_info_result (buf, reply_len); + g_assert (result); + + g_print ("\n"); + + str = NULL; + wmc_result_get_string (result, WMC_CMD_DEVICE_INFO_ITEM_MANUFACTURER, &str); + g_message ("%s: Manufacturer: %s", __func__, str); + + str = NULL; + wmc_result_get_string (result, WMC_CMD_DEVICE_INFO_ITEM_MODEL, &str); + g_message ("%s: Model: %s", __func__, str); + + str = NULL; + wmc_result_get_string (result, WMC_CMD_DEVICE_INFO_ITEM_FW_REVISION, &str); + g_message ("%s: FW Revision: %s", __func__, str); + + str = NULL; + wmc_result_get_string (result, WMC_CMD_DEVICE_INFO_ITEM_HW_REVISION, &str); + g_message ("%s: HW Revision: %s", __func__, str); + + wmc_result_unref (result); +} + diff --git a/libwmc/tests/test-wmc-com.h b/libwmc/tests/test-wmc-com.h index 9c6bd149..a26d364f 100644 --- a/libwmc/tests/test-wmc-com.h +++ b/libwmc/tests/test-wmc-com.h @@ -18,10 +18,14 @@ #ifndef TEST_WMC_COM_H #define TEST_WMC_COM_H -gpointer test_com_setup (const char *port, gboolean uml290); +gpointer test_com_setup (const char *port, gboolean uml290, gboolean debug); void test_com_teardown (gpointer d); void test_com_port_init (void *f, void *data); +void test_com_init (void *f, void *data); + +void test_com_device_info (void *f, void *data); + #endif /* TEST_WMC_COM_H */ diff --git a/libwmc/tests/test-wmc-utils.c b/libwmc/tests/test-wmc-utils.c index c38694ae..3a1d76be 100644 --- a/libwmc/tests/test-wmc-utils.c +++ b/libwmc/tests/test-wmc-utils.c @@ -126,8 +126,8 @@ test_utils_encapsulate_uml290_wmc1 (void *f, void *data) gsize encap_len = 0; memcpy (inbuf, uml290_encap_src, sizeof (uml290_encap_src)); - encap_len = uml290_wmc_encapsulate (inbuf, sizeof (uml290_encap_src), - sizeof (inbuf), outbuf, sizeof (outbuf)); + encap_len = wmc_encapsulate (inbuf, sizeof (uml290_encap_src), + sizeof (inbuf), outbuf, sizeof (outbuf), TRUE); g_assert (encap_len == sizeof (encap_outbuf)); g_assert (memcmp (outbuf, encap_outbuf, encap_len) == 0); } diff --git a/libwmc/tests/test-wmc.c b/libwmc/tests/test-wmc.c index 1c1921dd..91a2c271 100644 --- a/libwmc/tests/test-wmc.c +++ b/libwmc/tests/test-wmc.c @@ -36,7 +36,7 @@ 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, gboolean uml290) +test_data_new (const char *port, gboolean uml290, gboolean debug) { TestData *d; @@ -44,7 +44,7 @@ test_data_new (const char *port, gboolean uml290) g_assert (d); if (port) - d->com_data = test_com_setup (port, uml290); + d->com_data = test_com_setup (port, uml290, debug); return d; } @@ -65,7 +65,7 @@ int main (int argc, char **argv) int i; const char *port = NULL; gint result; - gboolean uml290 = FALSE; + gboolean uml290 = FALSE, debug = FALSE; g_test_init (&argc, &argv, NULL); @@ -77,9 +77,11 @@ int main (int argc, char **argv) port = argv[++i]; } else if (!strcmp (argv[i], "--uml290")) uml290 = TRUE; + else if (!strcmp (argv[i], "--debug")) + debug = TRUE; } - data = test_data_new (port, uml290); + data = test_data_new (port, uml290, debug); suite = g_test_get_root (); g_test_suite_add (suite, TESTCASE (test_crc16_1, NULL)); @@ -98,6 +100,8 @@ int main (int argc, char **argv) /* Live tests */ if (port) { g_test_suite_add (suite, TESTCASE (test_com_port_init, data->com_data)); + g_test_suite_add (suite, TESTCASE (test_com_init, data->com_data)); + g_test_suite_add (suite, TESTCASE (test_com_device_info, data->com_data)); } result = g_test_run (); |