WizziLab / modem_ref_v5_3_217

Dependents:   modem_ref_helper_for_v5_3_217

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers kal_codec.cpp Source File

kal_codec.cpp

00001 /// @copyright
00002 /// ========================================================================={{{
00003 /// Copyright (c) 20XX WizziLab                                                /
00004 /// All rights reserved                                                        /
00005 ///                                                                            /
00006 /// IMPORTANT: This Software may not be modified, copied or distributed unless /
00007 /// embedded on a WizziLab product. Other than for the foregoing purpose, this /
00008 /// Software and/or its documentation may not be used, reproduced, copied,     /
00009 /// prepared derivative works of, modified, performed, distributed, displayed  /
00010 /// or sold for any purpose. For the sole purpose of embedding this Software   /
00011 /// on a WizziLab product, copy, modification and distribution of this         /
00012 /// Software is granted provided that the following conditions are respected:  /
00013 ///                                                                            /
00014 /// *  Redistributions of source code must retain the above copyright notice,  /
00015 ///    this list of conditions and the following disclaimer                    /
00016 ///                                                                            /
00017 /// *  Redistributions in binary form must reproduce the above copyright       /
00018 ///    notice, this list of conditions and the following disclaimer in the     /
00019 ///    documentation and/or other materials provided with the distribution.    /
00020 ///                                                                            /
00021 /// *  The name of WizziLab can not be used to endorse or promote products     /
00022 ///    derived from this software without specific prior written permission.   /
00023 ///                                                                            /
00024 /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS        /
00025 /// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED  /
00026 /// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR /
00027 /// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR          /
00028 /// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,      /
00029 /// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,        /
00030 /// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,            /
00031 /// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     /
00032 /// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    /
00033 /// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS         /
00034 /// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.               /
00035 /// WIZZILAB HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,       /
00036 /// ENHANCEMENTS OR MODIFICATIONS.                                             /
00037 ///                                                                            /
00038 /// Should you have any questions regarding your right to use this Software,   /
00039 /// contact WizziLab at www.wizzilab.com.                                      /
00040 ///                                                                            /
00041 /// =========================================================================}}}
00042 /// @endcopyright
00043 ///
00044 /// =======================================================================
00045 ///
00046 /// @file           kal_codec.c
00047 /// @brief          Codec Utilities
00048 ///
00049 /// =======================================================================
00050 
00051 #include <string.h>
00052 #include "hal_types.h"
00053 #include "kal_codec.h"
00054 
00055 
00056 // ======================================================================
00057 //
00058 //
00059 //                  ASCII to Binary Codec Toolkits 
00060 //
00061 //
00062 // ======================================================================
00063 
00064 const char k_nybble_chars[] = "0123456789ABCDEF";
00065 
00066 //======================================================================
00067 // hex2ascii
00068 //----------------------------------------------------------------------
00069 /// @brief  Convert hexadecimal number to ascii
00070 /// @param  char* in        input buffer (hex)
00071 /// @param  char* out      output buffer (ascii)
00072 /// @param  u16 len         length of inoput buffer in bytes
00073 //======================================================================
00074 void hex2ascii( char* in, char* out, u16 length)
00075 {
00076     u8 b;
00077     while(length--) {
00078         b = *in++;
00079         *out++ = k_nybble_chars[ ( b >> 4 ) & 0x0F ];
00080         *out++ = k_nybble_chars[ b & 0x0F ];
00081     }
00082 }
00083 
00084 //======================================================================
00085 // itoa
00086 //----------------------------------------------------------------------
00087 /// @brief  Converts an integer value to a null-terminated string using the specified base and stores the result
00088 /// in the array given by result parameter.
00089 /// @param  int value       integer to convert
00090 /// @param  char* result    converted string
00091 /// @param  int base        base used for conversion 2, 8, 10, 16
00092 /// @return A pointer to the resulting null-terminated string, same as parameter result
00093 //======================================================================
00094 char* itoa(int value, char* result, int base) 
00095 {
00096     // check that the base if valid
00097     //if (base < 2 || base > 16) { return NULL; }
00098 
00099     char* ptr = result, *ptr1 = result, tmp_char;
00100     int tmp_value;
00101 
00102     do {
00103         tmp_value = value;
00104         value /= base;
00105         *ptr++ = "fedcba9876543210123456789abcdef" [15 + (tmp_value - value * base)];
00106     } while ( value );
00107 
00108     // Apply negative sign
00109     if (tmp_value < 0) *ptr++ = '-';
00110     //*ptr-- = '\0';
00111     result = ptr--;
00112     while(ptr1 < ptr) {
00113         tmp_char = *ptr;
00114         *ptr--= *ptr1;
00115         *ptr1++ = tmp_char;
00116     }
00117     return result;
00118 }
00119 
00120 //======================================================================
00121 // atoitok
00122 //----------------------------------------------------------------------
00123 /// @brief  Extracts from a ASCII string a value (decimal or hex) and
00124 ///         convert it to an integer value.
00125 ///         - Blank characters are skipped
00126 ///         - hexa values must begin with '0x' or '0X'
00127 ///         - '-' sign is handled
00128 ///         - returns after one value has been parsed or null character
00129 ///           or CR character has been found.
00130 /// @param  p pointer to pointer to the string to be parsed. The pointer
00131 ///         to string is modified: at the end of the call it points to
00132 ///         the character following the last parsed one.
00133 //======================================================================
00134 int atoitok(u8 **p)
00135 {
00136     int k = 0;
00137     u8 base16=0;
00138     s8 sign = 1;
00139     while ((**p==' ')||(**p=='\t')||(**p==',')) (*p)++;
00140     if (**p=='-')
00141     {
00142         sign = -1;
00143         (*p)++;
00144     }
00145     if ((**p=='0') && (*(*p+1)=='x'))
00146     {
00147         base16 = 1;
00148         *p += 2;
00149     }
00150     while (**p && **p!=' ' && **p!=0xa && **p!=',') {
00151         if (!base16)
00152         {
00153             k = (k<<3)+(k<<1)+(**p)-'0';
00154         }
00155         else
00156         {
00157             if (**p > '9')
00158                 if (**p > 'F')
00159                     k = (k<<4)+(10+(**p)-'a');
00160                 else
00161                     k = (k<<4)+(10+(**p)-'A');
00162             else
00163                 k = (k<<4)+(**p)-'0';
00164         }
00165         (*p)++;
00166     }
00167     return sign*k;
00168 }
00169 
00170 //======================================================================
00171 // kal_atoi
00172 //----------------------------------------------------------------------
00173 /// @brief  Extracts from a ASCII string a decimal value and
00174 ///         convert it to an integer value.
00175 ///         '-' and '+' signs are handled
00176 /// @param  s               char*                   string to convert
00177 /// @retval                 s32                     integer value
00178 //======================================================================
00179 s32 kal_atoi(u8* s)
00180 {
00181     s32 k = 0;
00182     s8 sign = 1;
00183 
00184     if (*s == '-')
00185     {
00186         sign = -1;
00187         s++;
00188     }
00189     else if (*s == '+')
00190     {
00191         s++;
00192     }
00193 
00194     while (*s >= '0' && *s <= '9')
00195     {
00196         k = 10 * k + *s - '0';
00197         s++;
00198     }
00199 
00200     return (sign * k);
00201 }
00202 
00203 //======================================================================
00204 // kal_atoi_float
00205 //----------------------------------------------------------------------
00206 /// @brief  Extracts from a ASCII string a float value and
00207 ///         convert it to an integer value * 10^number_of_decimals.
00208 ///         '-' and '+' signs are handled
00209 /// @param  s               char*                   string to convert
00210 /// @param  d               u8                      Number of decimals
00211 /// @retval                 s32                     integer value
00212 //======================================================================
00213 s32 kal_atoi_float(u8* s, u8 d)
00214 {
00215     s32 k_int = 0;
00216     s32 k_dec = 0;
00217     s8 sign = 1;
00218     u8 i;
00219 
00220     // Check sign
00221     if (*s == '-')
00222     {
00223         sign = -1;
00224         s++;
00225     }
00226     else if (*s == '+')
00227     {
00228         s++;
00229     }
00230 
00231     // Calculate integer part
00232     while (*s >= '0' && *s <= '9')
00233     {
00234         k_int = 10 * k_int + *s - '0';
00235         s++;
00236     }
00237 
00238     for (i = 0; i < d; i++)
00239     {
00240         k_int *= 10;
00241     }
00242 
00243     // Skip float separator
00244     if (*s == '.')
00245     {
00246         s++;
00247     }
00248     else
00249     {
00250         return (sign * k_int);
00251     }
00252 
00253     // Calculate decimal part
00254     while (*s >= '0' && *s <= '9' && d--)
00255     {
00256         k_dec = 10 * k_dec + *s - '0';
00257         s++;
00258     }
00259 
00260     // If string is finished but all the decimals aren't there, complete as if they were followed by 0s
00261     for (i = 0; i < d; i++)
00262     {
00263         k_dec *= 10;
00264     }
00265 
00266     return (sign * (k_int + k_dec));
00267 }
00268 //======================================================================
00269 // kal_atoi_hex
00270 //----------------------------------------------------------------------
00271 /// @brief  Extracts from a ASCII string a hex value and
00272 ///         convert it to an integer value.
00273 /// @param  s               char*                   string to convert
00274 /// @retval                 u32                     integer value
00275 //======================================================================
00276 u32 kal_atoi_hex(u8* s)
00277 {
00278     u32 k = 0;
00279 
00280     while (*s != '\0')
00281     {
00282         if (*s > '9')
00283         {
00284             k = 16 * k + 10 + (*s) - ((*s > 'F') ? 'a' : 'A');
00285         }
00286         else
00287         {
00288             k = 16 * k + (*s) - '0';
00289         }
00290         s++;
00291     }
00292 
00293     return (k);
00294 }
00295 
00296 //======================================================================
00297 // kal_base64_strlen
00298 //----------------------------------------------------------------------
00299 /// @brief  Real length (excluding padding) of Base64-encoded string
00300 ///         Note : the input string always has 4x chars, if not return 0
00301 /// @param  in              char*                   string to decode
00302 /// @retval                 u16                     string length
00303 //======================================================================
00304 u16 kal_base64_strlen(const char* in)
00305 {
00306     u16 len, j;
00307     register const char *p;
00308 
00309     // Useful strlen
00310     len = strlen(in);
00311 
00312     // the input string always has 4x chars
00313     if (len % 4)
00314     {
00315         return 0;
00316     }
00317 
00318     // remove padding
00319     for (j = 0, p = in + len - 1; len > 0 && *p == '=' ; j++, p--, len--) {;}
00320 
00321     // there is 0, 1 or 2 padding chars
00322     if (j > 2)
00323     {
00324         return 0;
00325     }
00326 
00327     return len;
00328 }
00329 
00330 //======================================================================
00331 // kal_base64 codec tables
00332 //======================================================================
00333 const char k_kal_base64_encode[] =  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00334 const u8   k_kal_base64_decode[] = {     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
00335                                          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
00336                                          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62, 63, 62, 62, 63,
00337                                         52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0,  0,  0,  0,
00338                                          0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
00339                                         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0, 63,
00340                                          0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
00341                                         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51     
00342                                     };
00343 
00344 //======================================================================
00345 // kal_base64_encode
00346 //----------------------------------------------------------------------
00347 /// @brief  Encode Base64-encoded buffer. The output buffer is supposed to have enough space
00348 ///         Beware, the stream encoding is Big Endian.
00349 /// @param  out             char*                   string result
00350 /// @param  in              u8*                     binary buffer to encode
00351 /// @param  len             u16                     length of the binary buffer in bytes
00352 /// @retval                 void 
00353 //======================================================================
00354 void kal_base64_encode(char *out, u8* in, u16 len)
00355 {
00356     u16 i = 0;
00357     register u8 a,b,c;
00358 
00359     if (len > 1)
00360     {
00361         for (; i < len - 2; i += 3) 
00362         {
00363             a = *in++;
00364             b = *in++;
00365             c = *in++;
00366             *out++ = k_kal_base64_encode[(((a >> 2) & 0x3F))];
00367             *out++ = k_kal_base64_encode[(((a << 4) & 0x30) | ((b >> 4) & 0x0F))];
00368             *out++ = k_kal_base64_encode[(((b << 2) & 0x3C) | ((c >> 6) & 0x03))];
00369             *out++ = k_kal_base64_encode[(((c >> 0) & 0x3F))];
00370         }
00371     }
00372 
00373     if (i < len) 
00374     {
00375         a = *in++;
00376         *out++ = k_kal_base64_encode[(((a >> 2) & 0x3F))];
00377 
00378         if (i == (len - 1)) 
00379         {
00380             *out++ = k_kal_base64_encode[(((a << 4) & 0x30))];
00381             *out++ = '=';
00382         }
00383         else 
00384         {
00385             b = *in++;
00386             *out++ = k_kal_base64_encode[(((a << 4) & 0x30) | ((b >> 4) & 0x0F))];
00387             *out++ = k_kal_base64_encode[(((b << 2) & 0x3C))];
00388         }
00389 
00390         *out++ = '=';
00391     }
00392 
00393     *out++ = '\0';
00394     return;
00395 }
00396 
00397 //======================================================================
00398 // kal_base64_decode
00399 //----------------------------------------------------------------------
00400 /// @brief  Decode Base64-encoded buffer. The output buffer is supposed to have enough space
00401 /// @param  out             u8*                     binary buffer result
00402 /// @param  in              char*                   string to decode
00403 /// @param  len             u16                     string length, excluding padding
00404 /// @retval                 void 
00405 //======================================================================
00406 void kal_base64_decode(u8 *out, const char* in, u16 len)
00407 {
00408     register u8 a,b,c,d;
00409 
00410     // Decode
00411     for (; len > 3; len -= 4)
00412     {
00413         a = k_kal_base64_decode[(u8)*in++];
00414         b = k_kal_base64_decode[(u8)*in++];
00415         c = k_kal_base64_decode[(u8)*in++];
00416         d = k_kal_base64_decode[(u8)*in++];
00417         
00418         *out++ = (a << 2) | (b >> 4);
00419         *out++ = (b << 4) | (c >> 2);
00420         *out++ = (c << 6) | (d >> 0);
00421     }
00422 
00423     // Note len == 1 is not possible 
00424     if (len > 1)
00425     {
00426         a = k_kal_base64_decode[(u8)*in++];
00427         b = k_kal_base64_decode[(u8)*in++];
00428         *out++ = (a << 2) | (b >> 4);
00429     }
00430     if (len > 2)
00431     {
00432         c = k_kal_base64_decode[(u8)*in++];
00433         *out++ = (b << 4) | (c >> 2);
00434     }
00435 }
00436 
00437 //======================================================================
00438 // kal_tolower
00439 //----------------------------------------------------------------------
00440 /// @brief  Changes inplace to lower character a non-constant string
00441 /// @param  s               u8*                     String to transform
00442 /// @retval                 void
00443 //======================================================================
00444 void kal_tolower(u8* s)
00445 {
00446     while (*s != '\0')
00447     {
00448         if (*s >= 'A' && *s <= 'Z')
00449         {
00450             *s += (u8)('a' - 'A');
00451         }
00452         s++;
00453     }
00454 }
00455 
00456 
00457 //======================================================================
00458 // kal_toupper
00459 //----------------------------------------------------------------------
00460 /// @brief  Changes inplace to upper character a non-constant string
00461 /// @param  s               u8*                     String to transform
00462 /// @retval                 void
00463 //======================================================================
00464 void kal_toupper(u8* s)
00465 {
00466     while (*s != '\0')
00467     {
00468         if (*s >= 'a' && *s <= 'z')
00469         {
00470             *s -= (u8)('a' - 'A');
00471         }
00472         s++;
00473     }
00474 }
00475 
00476 //======================================================================
00477 // kal_crc8
00478 //----------------------------------------------------------------------
00479 /// @brief  Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial.
00480 ///         A table-based algorithm would be faster, but for only a few
00481 ///         bytes it isn't worth the code size.
00482 /// @param  in          u8*                     input buffer
00483 /// @param  len         u32                     input buffer length in bytes
00484 /// @retval             void
00485 //======================================================================
00486 /* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial.  A
00487  * table-based algorithm would be faster, but for only a few bytes it isn't
00488  * worth the code size. */
00489 u8 kal_crc8(u8* in, u32 len) 
00490 {
00491     const u8 *data = in;
00492     u32 crc = 0;
00493     u8 i;
00494     u32 j;
00495 
00496     for (j = len; j; j--, data++)
00497     {
00498         crc ^= (*data << 8);
00499         for(i = 8; i; i--)
00500         {
00501             if (crc & 0x8000)
00502             {
00503                 crc ^= (0x1070 << 3);
00504             }
00505             crc <<= 1;
00506         }
00507     }
00508     return (u8)(crc >> 8);
00509 }
00510 
00511 //======================================================================
00512 // kal_ctf_encode
00513 //----------------------------------------------------------------------
00514 /// @brief  Compress u32 to D7A Compressed Time format (CTF).
00515 ///         The ceil flag is used to define rounding, so that 
00516 ///         kal_ctf_decode(kal_ctf_encode(val, FALSE) <= val (floor)
00517 ///         kal_ctf_decode(kal_ctf_encode(val, TRUE)  >= val (ceiling)
00518 /// @param  val         u32                     value to encode
00519 /// @param  ceil        u8                      ceil value when TRUE
00520 /// @retval             kal_ctf_t               compressed value 
00521 //======================================================================
00522 kal_ctf_t kal_ctf_encode(u32 val, u8 ceil)
00523 {
00524     u8 exp;
00525     u32 tmp = val;
00526     kal_ctf_t ctf;
00527     
00528     // serch best (smallest) exponent
00529     for (exp = 0; tmp > 31; exp++, tmp >>= 2) {};
00530     
00531     if (exp < 8)
00532     {
00533         ctf.bf.exp = exp;
00534         ctf.bf.mant = tmp;
00535 
00536         // manage floor
00537         if (ceil)
00538         {
00539             if (kal_ctf_decode(ctf) < val)
00540             { 
00541                 if (ctf.bf.mant < 31)
00542                 {
00543                     ctf.bf.mant++;
00544                 }
00545                 else
00546                 {
00547                     if (ctf.bf.exp < 7)
00548                     {
00549                         // mant = 31+1 = 4*8
00550                         ctf.bf.exp++;
00551                         ctf.bf.mant = 8;
00552                     }
00553                     else
00554                     {
00555                         // exp = 7+1 -> overflow
00556                         ctf.byte = 0xff;
00557                     }
00558                 }
00559             }
00560         }
00561     }
00562     else
00563     {
00564         ctf.byte = 0xff;
00565     }
00566 
00567     return ctf;
00568 }
00569 
00570 // =======================================================================
00571 // kal_ctf_decode
00572 // -----------------------------------------------------------------------
00573 /// @brief  Decompress from Compressed Time Format to u32
00574 /// @param  ctf         kal_ctf_t           compressed value in CTF
00575 /// @retval             u32                 decode result
00576 // =======================================================================
00577 u32 kal_ctf_decode(kal_ctf_t ctf)
00578 {
00579     return ((1 << (2*ctf.bf.exp)) * ctf.bf.mant);
00580 }
00581