Exportable version of WizziLab's modem driver.

Dependents:   modem_ref_helper

Revision:
19:701d5669f2e9
Parent:
16:3cdc2e00f5ed
Child:
26:2c934a269914
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/alp_helpers.cpp	Tue Dec 12 16:03:12 2017 +0000
@@ -0,0 +1,239 @@
+/// @copyright
+/// ========================================================================={{{
+/// Copyright (c) 2012-2017 WizziLab                                           /
+/// All rights reserved                                                        /
+///                                                                            /
+/// Should you have any questions regarding your right to use this Software,   /
+/// contact WizziLab at www.wizzilab.com.                                      /
+///                                                                            /
+/// =========================================================================}}}
+/// @endcopyright
+
+//  ====================================================================
+//  @file           alp_helpers.c
+//  @brief          ALP public helpers functions.
+//                  This code should be disclosable in source.
+//  ====================================================================
+
+
+#include "alp.h"
+
+//======================================================================
+// alp_size
+//----------------------------------------------------------------------
+/// @brief Return payload length of most ALP operations
+/// @param op       : ALP Action amongst alp_opcodes_t
+/// @param offset   : Associated Offset if relevant
+/// @param size     : Associated Size if relevant
+/// @retval payload size in bytes
+//======================================================================
+public uint alp_size(u8 op, u32 offset, u32 length)
+{
+    uint len=2;// At least OP+FID / OP+TAG
+    switch (op)
+    {
+        case ALP_OPCODE_NOP:
+        case ALP_OPCODE_F_TOUCH:
+        case ALP_OPCODE_F_EXIST:
+        case ALP_OPCODE_F_DELETE:
+        case ALP_OPCODE_F_FLUSH:
+        case ALP_OPCODE_RSP_TAG:
+        case ALP_OPCODE_F_RD_PROP:
+            break;
+        case ALP_OPCODE_RSP_STATUS:
+            len += 1;
+            break;
+        case ALP_OPCODE_F_CREATE:
+        case ALP_OPCODE_F_DECLARE:
+        case ALP_OPCODE_RSP_F_PROP:
+            len += ALP_FILE_HEADER_SIZE;
+            break;
+        case ALP_OPCODE_F_WR_PROP:
+        case ALP_OPCODE_F_WR_DATA:
+        case ALP_OPCODE_RSP_F_DATA:
+            len = length;
+        case ALP_OPCODE_F_RD_DATA:
+            len += ALP_LFIELD_SIZE(offset) + ALP_LFIELD_SIZE(length);
+            break;
+        default:
+            //ASSERT(false,"ASSERT: ALP: alp_size unsupported op %d\n",op);
+            break;
+    }
+    return len;
+}
+
+//======================================================================
+// alp_encode_length
+//----------------------------------------------------------------------
+/// @brief Encodes an ALP length/offset field
+/// @param p        : pointer to the payload buffer
+/// @param len      : value to be encoded
+/// @retval resulting payload size in bytes
+//======================================================================
+public u8 alp_encode_length(u8* p, u32 len)
+{
+    if (len <= 0x3F)
+    {
+        *p++ = len;
+        return 1;
+    }
+    else if (len <= 0x3FFF)
+    {
+        *p++ = 0x40 + (u8)(len >> 8);
+        *p++ =        (u8)(len & 0xFF);
+        return 2;
+    }
+    else if (len <= 0x3FFFFF)
+    {
+        *p++ = 0x80 + (u8) (len >> 16);
+        *p++ =        (u8)((len >> 8) & 0xFF);
+        *p++ =        (u8) (len       & 0xFF);
+        return 3;
+    }
+    else
+    {
+        *p++ = 0xC0 + (u8) (len >> 24);
+        *p++ =        (u8)((len >> 16) & 0xFF);
+        *p++ =        (u8)((len >>  8) & 0xFF);
+        *p++ =        (u8) (len        & 0xFF);
+        return 4;
+    }
+}
+
+
+//======================================================================
+// alp_decode_length
+//----------------------------------------------------------------------
+/// @brief Decodes an ALP length/offset field
+/// @param p        : pointer to the pointer to payload buffer
+/// @param actp     : pointer to ALP's Action Protocol Substitution flag
+///                   Result amongst alp_actp_substitution_mode_t
+/// @retval decoded value
+//======================================================================
+public u32 alp_decode_length(u8** p, u8* actp)
+{
+    u32 tmp = 0;
+    switch ((**p) & 0xC0)
+    {
+        case 0xC0: // 0xCx xx xx xx
+            tmp  = ((*(*p)++) & 0x3F) << 24;
+            tmp +=  (*(*p)++)         << 16;
+            tmp +=  (*(*p)++)         <<  8;
+            tmp +=  (*(*p)++)         <<  0;
+            break;
+        case 0x80: // 0x8x xx xx : 16384 <= Len <4194303
+            tmp  = ((*(*p)++) & 0x3F) << 16;
+            tmp +=  (*(*p)++)         <<  8;
+            if (tmp == 0)
+            {
+                // 0x8000 ActP special ActP code
+                // Do not fetch the extra byte
+                *actp = 2;
+            }
+            else
+            {
+                tmp +=  (*(*p)++)     <<  0;
+            }
+            break;
+        case 0x40: // 0x4x xx : 64 <= Len < 16383
+            tmp  = ((*(*p)++) & 0x3F) <<  8;
+            tmp +=  (*(*p)++)         <<  0;
+            if (tmp == 0)
+            {
+                // 0x4000 ActP special ActP code
+                *actp = 1;
+            }
+            break;
+        case 0: // Len <63
+            tmp  = (*(*p)++ & 0x3F) <<  0;
+            break;
+    }
+    return tmp;
+}
+
+
+//======================================================================
+// alp_parse_chunk
+//----------------------------------------------------------------------
+/// @brief Parses an ALP payload and extract a single chunk (action or
+///        response) to a more generic alp_parsed_chunk_t structure.
+/// @param payload  : pointer to the pointer to payload buffer
+/// @param resp     : pointer to alp_parsed_chunk_t structure
+/// @retval number of parsed bytes
+//======================================================================
+public int alp_parse_chunk(u8** payload, alp_parsed_chunk_t* resp) // {{{
+{
+    u8* p = *payload;
+    u8 op = *p++;
+    u8 actp;
+    u32 bytes;
+    resp->type = op & 0x3F;
+    resp->data = (u8*)NULL;
+    switch(resp->type) // XXX preemption bits squashed
+    {
+        case ALP_OPCODE_RSP_TAG:
+        case ALP_OPCODE_TAG:
+            resp->meta.tag.id  = *p++; // PID
+            resp->meta.tag.eop = !!(op & ALP_OPCODE_EOP);
+            resp->meta.tag.err = !!(op & ALP_OPCODE_ERR);
+            break;
+        case ALP_OPCODE_RSP_F_DATA:
+        case ALP_OPCODE_F_WR_DATA:
+            resp->meta.f_data.fid = *p++; // FID
+            resp->meta.f_data.offset = alp_decode_length(&p,&actp); // Offset
+            resp->meta.f_data.length = alp_decode_length(&p,&actp); // Length
+            resp->data = p;
+            p += resp->meta.f_data.length;
+            break;
+        case ALP_OPCODE_F_RD_DATA:
+            resp->meta.f_data.fid = *p++; // FID
+            resp->meta.f_data.offset = alp_decode_length(&p,&actp); // Offset
+            resp->meta.f_data.length = alp_decode_length(&p,&actp); // Length
+            break;
+        case ALP_OPCODE_F_RD_PROP:
+            resp->meta.f_prop.fid = *p++; // FID
+            resp->meta.f_prop.offset = 0;
+            resp->meta.f_prop.length = ALP_FILE_HEADER_SIZE; // Hardcoded Length
+            break;
+        case ALP_OPCODE_RSP_F_PROP:
+            resp->meta.f_prop.fid = *p++; // FID
+            resp->meta.f_prop.offset = 0;
+            resp->meta.f_prop.length = ALP_FILE_HEADER_SIZE; // Hardcoded Length
+            resp->data = p;
+            p += resp->meta.f_prop.length;
+            break;
+        case ALP_OPCODE_RSP_STATUS:
+            if (op == ALP_OPCODE_RSP_ISTATUS)
+            {
+                resp->type = ALP_OPCODE_RSP_ISTATUS;
+                resp->meta.itf.type = *p++; // ITF Type
+                resp->meta.itf.length = alp_decode_length(&p,&actp); // Length
+                resp->data = p;
+                p += resp->meta.itf.length;
+            }
+            else
+            {
+                resp->meta.status.id = *p++; // Action ID
+                resp->meta.status.code = *p++; // status
+            }
+            break;
+        case ALP_OPCODE_RSP_URC:
+            resp->meta.urc.type = *p++; // Type
+            resp->meta.urc.ifid = *p++; // Ifid
+            if (resp->meta.urc.type == ALP_URC_TYPE_LQUAL)
+                resp->meta.urc.per = *p++; // Per
+            break;
+        case ALP_OPCODE_F_DELETE:
+        case ALP_OPCODE_F_FLUSH:
+            resp->meta.f_data.fid = *p++; // FID
+            break;
+        default:
+            resp->type = ALP_OPCODE_UNKNOWN;
+            *payload = (u8*)NULL;
+            return 0;
+    }
+    bytes = p - *payload;
+    *payload = p;
+    return bytes;
+} // }}}
+