Exportable version of WizziLab's modem driver.
src/alp_helpers.cpp
- Committer:
- Jeej
- Date:
- 2017-12-12
- Revision:
- 19:701d5669f2e9
- Parent:
- alp_helpers.cpp@ 16:3cdc2e00f5ed
- Child:
- 26:2c934a269914
File content as of revision 19:701d5669f2e9:
/// @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; } // }}}