From 942bdeaec26eb587f39e9709dff0174bc4bfdd42 Mon Sep 17 00:00:00 2001
From: Ben Chan <benchan@chromium.org>
Date: Sat, 20 Oct 2018 20:20:54 -0700
Subject: [PATCH] modem-helpers: new helper to convert binary-coded decimals

This patch adds a mm_bcd_to_string() helper function to convert a byte
array representing a binary-coded decimal (BCD) number to a string
representing the equivalent decimal number.
---
 src/mm-modem-helpers.c         | 20 ++++++++++++++++++
 src/mm-modem-helpers.h         |  2 ++
 src/tests/test-modem-helpers.c | 38 ++++++++++++++++++++++++++++++++++
 3 files changed, 60 insertions(+)

diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 7845edcff5..87e3754a68 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -496,6 +496,26 @@ mm_filter_supported_capabilities (MMModemCapability all,
 
 /*****************************************************************************/
 
+static const gchar bcd_chars[] = "0123456789\0\0\0\0\0\0";
+
+gchar *
+mm_bcd_to_string (const guint8 *bcd, gsize bcd_len)
+{
+    GString *str;
+    gsize i;
+
+    g_return_val_if_fail (bcd != NULL, NULL);
+
+    str = g_string_sized_new (bcd_len * 2 + 1);
+    for (i = 0 ; i < bcd_len; i++) {
+        str = g_string_append_c (str, bcd_chars[bcd[i] & 0xF]);
+        str = g_string_append_c (str, bcd_chars[(bcd[i] >> 4) & 0xF]);
+    }
+    return g_string_free (str, FALSE);
+}
+
+/*****************************************************************************/
+
 GRegex *
 mm_voice_ring_regex_get (void)
 {
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index a2ee825417..71d8893ea8 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -88,6 +88,8 @@ GArray *mm_filter_supported_modes (const GArray *all,
 GArray *mm_filter_supported_capabilities (MMModemCapability all,
                                           const GArray *supported_combinations);
 
+gchar *mm_bcd_to_string (const guint8 *bcd, gsize bcd_len);
+
 /*****************************************************************************/
 /* VOICE specific helpers and utilities */
 /*****************************************************************************/
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index 88f5a060bb..598e535058 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -3815,6 +3815,42 @@ test_parse_uint_list (void)
 
 /*****************************************************************************/
 
+typedef struct {
+    const guint8 bcd[10];
+    gsize bcd_len;
+    const gchar *str;
+} BcdToStringTest;
+
+static const BcdToStringTest bcd_to_string_tests[] = {
+    { { }, 0, "" },
+    { { 0x01 }, 1, "10" },
+    { { 0x1F }, 1, "" },
+    { { 0xE2 }, 1, "2" },
+    { { 0xD3 }, 1, "3" },
+    { { 0xC4 }, 1, "4" },
+    { { 0xB1, 0x23 }, 2, "1" },
+    { { 0x01, 0x23, 0x45, 0x67 }, 4, "10325476" },
+    { { 0x01, 0x23, 0x45, 0xA7 }, 4, "1032547" },
+    { { 0x01, 0x23, 0x45, 0x67 }, 2, "1032" },
+};
+
+static void
+test_bcd_to_string (void *f, gpointer d)
+{
+    guint i;
+
+    for (i = 0; i < G_N_ELEMENTS (bcd_to_string_tests); i++) {
+        gchar *str;
+
+        str = mm_bcd_to_string (bcd_to_string_tests[i].bcd,
+                                bcd_to_string_tests[i].bcd_len);
+        g_assert_cmpstr (str, ==, bcd_to_string_tests[i].str);
+        g_free (str);
+    }
+}
+
+/*****************************************************************************/
+
 void
 _mm_log (const char *loc,
          const char *func,
@@ -4045,6 +4081,8 @@ int main (int argc, char **argv)
 
     g_test_suite_add (suite, TESTCASE (test_parse_uint_list, NULL));
 
+    g_test_suite_add (suite, TESTCASE (test_bcd_to_string, NULL));
+
     result = g_test_run ();
 
     reg_test_data_free (reg_data);
-- 
GitLab