Exportable version of WizziLab's modem driver.

Dependents:   modem_ref_helper

Revision:
41:6f83174ffed4
diff -r 62b7f6d25772 -r 6f83174ffed4 src/kal_codec.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kal_codec.cpp	Mon Nov 26 16:42:16 2018 +0000
@@ -0,0 +1,581 @@
+/// @copyright
+/// ========================================================================={{{
+/// Copyright (c) 20XX WizziLab                                                /
+/// All rights reserved                                                        /
+///                                                                            /
+/// IMPORTANT: This Software may not be modified, copied or distributed unless /
+/// embedded on a WizziLab product. Other than for the foregoing purpose, this /
+/// Software and/or its documentation may not be used, reproduced, copied,     /
+/// prepared derivative works of, modified, performed, distributed, displayed  /
+/// or sold for any purpose. For the sole purpose of embedding this Software   /
+/// on a WizziLab product, copy, modification and distribution of this         /
+/// Software is granted provided that the following conditions are respected:  /
+///                                                                            /
+/// *  Redistributions of source code must retain the above copyright notice,  /
+///    this list of conditions and the following disclaimer                    /
+///                                                                            /
+/// *  Redistributions in binary form must reproduce the above copyright       /
+///    notice, this list of conditions and the following disclaimer in the     /
+///    documentation and/or other materials provided with the distribution.    /
+///                                                                            /
+/// *  The name of WizziLab can not be used to endorse or promote products     /
+///    derived from this software without specific prior written permission.   /
+///                                                                            /
+/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS        /
+/// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED  /
+/// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR /
+/// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR          /
+/// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,      /
+/// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,        /
+/// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,            /
+/// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     /
+/// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    /
+/// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS         /
+/// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.               /
+/// WIZZILAB HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,       /
+/// ENHANCEMENTS OR MODIFICATIONS.                                             /
+///                                                                            /
+/// Should you have any questions regarding your right to use this Software,   /
+/// contact WizziLab at www.wizzilab.com.                                      /
+///                                                                            /
+/// =========================================================================}}}
+/// @endcopyright
+///
+/// =======================================================================
+///
+/// @file           kal_codec.c
+/// @brief          Codec Utilities
+///
+/// =======================================================================
+
+#include <string.h>
+#include "hal_types.h"
+#include "kal_codec.h"
+
+
+// ======================================================================
+//
+//
+//                  ASCII to Binary Codec Toolkits 
+//
+//
+// ======================================================================
+
+const char k_nybble_chars[] = "0123456789ABCDEF";
+
+//======================================================================
+// hex2ascii
+//----------------------------------------------------------------------
+/// @brief  Convert hexadecimal number to ascii
+/// @param  char* in        input buffer (hex)
+/// @param  char* out      output buffer (ascii)
+/// @param  u16 len         length of inoput buffer in bytes
+//======================================================================
+void hex2ascii( char* in, char* out, u16 length)
+{
+    u8 b;
+    while(length--) {
+        b = *in++;
+        *out++ = k_nybble_chars[ ( b >> 4 ) & 0x0F ];
+        *out++ = k_nybble_chars[ b & 0x0F ];
+    }
+}
+
+//======================================================================
+// itoa
+//----------------------------------------------------------------------
+/// @brief  Converts an integer value to a null-terminated string using the specified base and stores the result
+/// in the array given by result parameter.
+/// @param  int value       integer to convert
+/// @param  char* result    converted string
+/// @param  int base        base used for conversion 2, 8, 10, 16
+/// @return A pointer to the resulting null-terminated string, same as parameter result
+//======================================================================
+char* itoa(int value, char* result, int base) 
+{
+    // check that the base if valid
+    //if (base < 2 || base > 16) { return NULL; }
+
+    char* ptr = result, *ptr1 = result, tmp_char;
+    int tmp_value;
+
+    do {
+        tmp_value = value;
+        value /= base;
+        *ptr++ = "fedcba9876543210123456789abcdef" [15 + (tmp_value - value * base)];
+    } while ( value );
+
+    // Apply negative sign
+    if (tmp_value < 0) *ptr++ = '-';
+    //*ptr-- = '\0';
+    result = ptr--;
+    while(ptr1 < ptr) {
+        tmp_char = *ptr;
+        *ptr--= *ptr1;
+        *ptr1++ = tmp_char;
+    }
+    return result;
+}
+
+//======================================================================
+// atoitok
+//----------------------------------------------------------------------
+/// @brief  Extracts from a ASCII string a value (decimal or hex) and
+///         convert it to an integer value.
+///         - Blank characters are skipped
+///         - hexa values must begin with '0x' or '0X'
+///         - '-' sign is handled
+///         - returns after one value has been parsed or null character
+///           or CR character has been found.
+/// @param  p pointer to pointer to the string to be parsed. The pointer
+///         to string is modified: at the end of the call it points to
+///         the character following the last parsed one.
+//======================================================================
+int atoitok(u8 **p)
+{
+    int k = 0;
+    u8 base16=0;
+    s8 sign = 1;
+    while ((**p==' ')||(**p=='\t')||(**p==',')) (*p)++;
+    if (**p=='-')
+    {
+        sign = -1;
+        (*p)++;
+    }
+    if ((**p=='0') && (*(*p+1)=='x'))
+    {
+        base16 = 1;
+        *p += 2;
+    }
+    while (**p && **p!=' ' && **p!=0xa && **p!=',') {
+        if (!base16)
+        {
+            k = (k<<3)+(k<<1)+(**p)-'0';
+        }
+        else
+        {
+            if (**p > '9')
+                if (**p > 'F')
+                    k = (k<<4)+(10+(**p)-'a');
+                else
+                    k = (k<<4)+(10+(**p)-'A');
+            else
+                k = (k<<4)+(**p)-'0';
+        }
+        (*p)++;
+    }
+    return sign*k;
+}
+
+//======================================================================
+// kal_atoi
+//----------------------------------------------------------------------
+/// @brief  Extracts from a ASCII string a decimal value and
+///         convert it to an integer value.
+///         '-' and '+' signs are handled
+/// @param  s               char*                   string to convert
+/// @retval                 s32                     integer value
+//======================================================================
+s32 kal_atoi(u8* s)
+{
+    s32 k = 0;
+    s8 sign = 1;
+
+    if (*s == '-')
+    {
+        sign = -1;
+        s++;
+    }
+    else if (*s == '+')
+    {
+        s++;
+    }
+
+    while (*s >= '0' && *s <= '9')
+    {
+        k = 10 * k + *s - '0';
+        s++;
+    }
+
+    return (sign * k);
+}
+
+//======================================================================
+// kal_atoi_float
+//----------------------------------------------------------------------
+/// @brief  Extracts from a ASCII string a float value and
+///         convert it to an integer value * 10^number_of_decimals.
+///         '-' and '+' signs are handled
+/// @param  s               char*                   string to convert
+/// @param  d               u8                      Number of decimals
+/// @retval                 s32                     integer value
+//======================================================================
+s32 kal_atoi_float(u8* s, u8 d)
+{
+    s32 k_int = 0;
+    s32 k_dec = 0;
+    s8 sign = 1;
+    u8 i;
+
+    // Check sign
+    if (*s == '-')
+    {
+        sign = -1;
+        s++;
+    }
+    else if (*s == '+')
+    {
+        s++;
+    }
+
+    // Calculate integer part
+    while (*s >= '0' && *s <= '9')
+    {
+        k_int = 10 * k_int + *s - '0';
+        s++;
+    }
+
+    for (i = 0; i < d; i++)
+    {
+        k_int *= 10;
+    }
+
+    // Skip float separator
+    if (*s == '.')
+    {
+        s++;
+    }
+    else
+    {
+        return (sign * k_int);
+    }
+
+    // Calculate decimal part
+    while (*s >= '0' && *s <= '9' && d--)
+    {
+        k_dec = 10 * k_dec + *s - '0';
+        s++;
+    }
+
+    // If string is finished but all the decimals aren't there, complete as if they were followed by 0s
+    for (i = 0; i < d; i++)
+    {
+        k_dec *= 10;
+    }
+
+    return (sign * (k_int + k_dec));
+}
+//======================================================================
+// kal_atoi_hex
+//----------------------------------------------------------------------
+/// @brief  Extracts from a ASCII string a hex value and
+///         convert it to an integer value.
+/// @param  s               char*                   string to convert
+/// @retval                 u32                     integer value
+//======================================================================
+u32 kal_atoi_hex(u8* s)
+{
+    u32 k = 0;
+
+    while (*s != '\0')
+    {
+        if (*s > '9')
+        {
+            k = 16 * k + 10 + (*s) - ((*s > 'F') ? 'a' : 'A');
+        }
+        else
+        {
+            k = 16 * k + (*s) - '0';
+        }
+        s++;
+    }
+
+    return (k);
+}
+
+//======================================================================
+// kal_base64_strlen
+//----------------------------------------------------------------------
+/// @brief  Real length (excluding padding) of Base64-encoded string
+///         Note : the input string always has 4x chars, if not return 0
+/// @param  in              char*                   string to decode
+/// @retval                 u16                     string length
+//======================================================================
+u16 kal_base64_strlen(const char* in)
+{
+    u16 len, j;
+    register const char *p;
+
+    // Useful strlen
+    len = strlen(in);
+
+    // the input string always has 4x chars
+    if (len % 4)
+    {
+        return 0;
+    }
+
+    // remove padding
+    for (j = 0, p = in + len - 1; len > 0 && *p == '=' ; j++, p--, len--) {;}
+
+    // there is 0, 1 or 2 padding chars
+    if (j > 2)
+    {
+        return 0;
+    }
+
+    return len;
+}
+
+//======================================================================
+// kal_base64 codec tables
+//======================================================================
+const char k_kal_base64_encode[] =  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+const u8   k_kal_base64_decode[] = {     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                                         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                                         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62, 63, 62, 62, 63,
+                                        52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0,  0,  0,  0,
+                                         0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+                                        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0, 63,
+                                         0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+                                        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51     
+                                    };
+
+//======================================================================
+// kal_base64_encode
+//----------------------------------------------------------------------
+/// @brief  Encode Base64-encoded buffer. The output buffer is supposed to have enough space
+///         Beware, the stream encoding is Big Endian.
+/// @param  out             char*                   string result
+/// @param  in              u8*                     binary buffer to encode
+/// @param  len             u16                     length of the binary buffer in bytes
+/// @retval                 void 
+//======================================================================
+void kal_base64_encode(char *out, u8* in, u16 len)
+{
+    u16 i = 0;
+    register u8 a,b,c;
+
+    if (len > 1)
+    {
+        for (; i < len - 2; i += 3) 
+        {
+            a = *in++;
+            b = *in++;
+            c = *in++;
+            *out++ = k_kal_base64_encode[(((a >> 2) & 0x3F))];
+            *out++ = k_kal_base64_encode[(((a << 4) & 0x30) | ((b >> 4) & 0x0F))];
+            *out++ = k_kal_base64_encode[(((b << 2) & 0x3C) | ((c >> 6) & 0x03))];
+            *out++ = k_kal_base64_encode[(((c >> 0) & 0x3F))];
+        }
+    }
+
+    if (i < len) 
+    {
+        a = *in++;
+        *out++ = k_kal_base64_encode[(((a >> 2) & 0x3F))];
+
+        if (i == (len - 1)) 
+        {
+            *out++ = k_kal_base64_encode[(((a << 4) & 0x30))];
+            *out++ = '=';
+        }
+        else 
+        {
+            b = *in++;
+            *out++ = k_kal_base64_encode[(((a << 4) & 0x30) | ((b >> 4) & 0x0F))];
+            *out++ = k_kal_base64_encode[(((b << 2) & 0x3C))];
+        }
+
+        *out++ = '=';
+    }
+
+    *out++ = '\0';
+    return;
+}
+
+//======================================================================
+// kal_base64_decode
+//----------------------------------------------------------------------
+/// @brief  Decode Base64-encoded buffer. The output buffer is supposed to have enough space
+/// @param  out             u8*                     binary buffer result
+/// @param  in              char*                   string to decode
+/// @param  len             u16                     string length, excluding padding
+/// @retval                 void 
+//======================================================================
+void kal_base64_decode(u8 *out, const char* in, u16 len)
+{
+    register u8 a,b,c,d;
+
+    // Decode
+    for (; len > 3; len -= 4)
+    {
+        a = k_kal_base64_decode[(u8)*in++];
+        b = k_kal_base64_decode[(u8)*in++];
+        c = k_kal_base64_decode[(u8)*in++];
+        d = k_kal_base64_decode[(u8)*in++];
+        
+        *out++ = (a << 2) | (b >> 4);
+        *out++ = (b << 4) | (c >> 2);
+        *out++ = (c << 6) | (d >> 0);
+    }
+
+    // Note len == 1 is not possible 
+    if (len > 1)
+    {
+        a = k_kal_base64_decode[(u8)*in++];
+        b = k_kal_base64_decode[(u8)*in++];
+        *out++ = (a << 2) | (b >> 4);
+    }
+    if (len > 2)
+    {
+        c = k_kal_base64_decode[(u8)*in++];
+        *out++ = (b << 4) | (c >> 2);
+    }
+}
+
+//======================================================================
+// kal_tolower
+//----------------------------------------------------------------------
+/// @brief  Changes inplace to lower character a non-constant string
+/// @param  s               u8*                     String to transform
+/// @retval                 void
+//======================================================================
+void kal_tolower(u8* s)
+{
+    while (*s != '\0')
+    {
+        if (*s >= 'A' && *s <= 'Z')
+        {
+            *s += (u8)('a' - 'A');
+        }
+        s++;
+    }
+}
+
+
+//======================================================================
+// kal_toupper
+//----------------------------------------------------------------------
+/// @brief  Changes inplace to upper character a non-constant string
+/// @param  s               u8*                     String to transform
+/// @retval                 void
+//======================================================================
+void kal_toupper(u8* s)
+{
+    while (*s != '\0')
+    {
+        if (*s >= 'a' && *s <= 'z')
+        {
+            *s -= (u8)('a' - 'A');
+        }
+        s++;
+    }
+}
+
+//======================================================================
+// kal_crc8
+//----------------------------------------------------------------------
+/// @brief  Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial.
+///         A table-based algorithm would be faster, but for only a few
+///         bytes it isn't worth the code size.
+/// @param  in          u8*                     input buffer
+/// @param  len         u32                     input buffer length in bytes
+/// @retval             void
+//======================================================================
+/* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial.  A
+ * table-based algorithm would be faster, but for only a few bytes it isn't
+ * worth the code size. */
+u8 kal_crc8(u8* in, u32 len) 
+{
+    const u8 *data = in;
+    u32 crc = 0;
+    u8 i;
+    u32 j;
+
+    for (j = len; j; j--, data++)
+    {
+        crc ^= (*data << 8);
+        for(i = 8; i; i--)
+        {
+            if (crc & 0x8000)
+            {
+                crc ^= (0x1070 << 3);
+            }
+            crc <<= 1;
+        }
+    }
+    return (u8)(crc >> 8);
+}
+
+//======================================================================
+// kal_ctf_encode
+//----------------------------------------------------------------------
+/// @brief  Compress u32 to D7A Compressed Time format (CTF).
+///         The ceil flag is used to define rounding, so that 
+///         kal_ctf_decode(kal_ctf_encode(val, FALSE) <= val (floor)
+///         kal_ctf_decode(kal_ctf_encode(val, TRUE)  >= val (ceiling)
+/// @param  val         u32                     value to encode
+/// @param  ceil        u8                      ceil value when TRUE
+/// @retval             kal_ctf_t               compressed value 
+//======================================================================
+kal_ctf_t kal_ctf_encode(u32 val, u8 ceil)
+{
+    u8 exp;
+    u32 tmp = val;
+    kal_ctf_t ctf;
+    
+    // serch best (smallest) exponent
+    for (exp = 0; tmp > 31; exp++, tmp >>= 2) {};
+    
+    if (exp < 8)
+    {
+        ctf.bf.exp = exp;
+        ctf.bf.mant = tmp;
+
+        // manage floor
+        if (ceil)
+        {
+            if (kal_ctf_decode(ctf) < val)
+            { 
+                if (ctf.bf.mant < 31)
+                {
+                    ctf.bf.mant++;
+                }
+                else
+                {
+                    if (ctf.bf.exp < 7)
+                    {
+                        // mant = 31+1 = 4*8
+                        ctf.bf.exp++;
+                        ctf.bf.mant = 8;
+                    }
+                    else
+                    {
+                        // exp = 7+1 -> overflow
+                        ctf.byte = 0xff;
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        ctf.byte = 0xff;
+    }
+
+    return ctf;
+}
+
+// =======================================================================
+// kal_ctf_decode
+// -----------------------------------------------------------------------
+/// @brief  Decompress from Compressed Time Format to u32
+/// @param  ctf         kal_ctf_t           compressed value in CTF
+/// @retval             u32                 decode result
+// =======================================================================
+u32 kal_ctf_decode(kal_ctf_t ctf)
+{
+    return ((1 << (2*ctf.bf.exp)) * ctf.bf.mant);
+}
+